Frage

Ich bin mit 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 folgt 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 wie folgt konfiguriert:

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

Ich habe Pyodbc 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 installierte auf meinem lokalen Netzwerk, und auf der lokalen IP-Adresse 10.32.42.69 hören. Ich habe eine leere Datenbank mit dem Namen „Common“ erstellt. Ich habe den Benutzer „sa“ mit dem Passwort „secret“ mit voller priviledges.

Ich bin mit dem folgenden Python-Code zum Einrichten der Verbindung:

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 WERKE bis zu diesem Punkt. Ich habe SQLServer Enterprise Manager auf dem Server und die neue Tabelle ist dort verwendet. Jetzt möchte ich einige Daten auf den Tisch legen.

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

Das versagt !! Hier ist der Fehler, den ich bekommen:

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

Da mein Client konfiguriert ist, UTF-8 zu verwenden, ich dachte, dass ich durch die Codierung Daten in UTF-8 lösen könnte. Das funktioniert, aber dann komme ich wieder seltsame Daten:

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 Daten zurückgegeben wird, ist nicht die gleichen Daten gesendet! Erhalte ich:

<type 'unicode'> somé string

Das heißt, Pyodbc wird ein Unicode-Objekt nicht direkt annehmen, aber es gibt Unicode mir Objekte zurück! Und die Codierung gemischt wird!

Nun zur Frage:

Ich mag Code Unicode-Daten in einem NVARCHAR und / oder NTEXT Feld einfügen. Wenn ich Abfrage zurück, ich mag die gleichen Daten ich wieder eingefügt.

Das von der Konfiguration des Systems unterschiedlich sein kann, oder durch eine Wrapper-Funktion kann unter Verwendung der Daten korrekt zu / von Unicode umwandeln beim Einfügen oder Abrufen von

nicht, das ist zu fragen viel, ist es?

War es hilfreich?

Lösung

ich mich erinnern kann, diese Art von dummen Problemen mit ODBC-Treiber, auch wenn dieses Mal ist es eine Java + Orakel Kombination war.

Der Kern ist, dass ODBC-Treiber anscheinend den Query-String codieren, wenn es an die DB zu senden. Auch wenn das Feld Unicode, und wenn Sie Unicode bieten, in einigen Fällen ist es keine Rolle zu spielen.

Sie müssen sicherstellen, dass durch den Fahrer, was gesendet wird die gleiche Codierung wie Ihre Datenbank (nicht nur Server, sondern auch Datenbank). Ansonsten natürlich erhalten Sie funky Zeichen, weil entweder der Client oder der Server Dinge mischen, wenn Codierung / oder Decodierung. Haben Sie eine Ahnung von der charset haben (Codepoint als MS gerne sagen), dass Ihr Server verwendet als Standard zum Dekodieren von Daten?

Sortierungs hat nichts mit diesem Problem zu tun:)

Siehe dass MS zum Beispiel. Für Unicode-Felder, Sortierung nur dann verwendet wird, um die Sortierreihenfolge in der Spalte zu definieren, nicht , um festzulegen, wie die Daten gespeichert werden.

Wenn Sie Ihre Daten als Unicode gibt es eine einzigartige Art und Weise zu repräsentieren, das ist der Zweck von Unicode: keine Notwendigkeit, eine charset zu definieren, die mit allen Sprachen kompatibel ist, die Sie verwenden wollen :)

Die Frage ist: „Was passiert, wenn ich Daten an den Server geben, die nicht Unicode?“. Zum Beispiel:

  • Wenn ich eine UTF-8-String an den Server senden, wie funktioniert sie es verstehen?
  • Wenn ich ein UTF-16-String an den Server senden, wie funktioniert sie es verstehen?
  • Wenn ich eine Latin1 Zeichenfolge an den Server senden, wie funktioniert sie es verstehen?

Aus der Perspektive des Servers, alle diese drei Saiten sind nur ein Strom von Bytes. Der Server kann nicht erraten, die Codierung, in der sie codiert. Was bedeutet, dass Sie wird bekommen Probleme, wenn Ihr odbc Client sendet endet bytestrings (eine codierte Zeichenfolge) an den Server statt Senden Unicode Daten: wenn Sie dies tun, werden der Server eine vordefinierte Codierung verwenden (das war meine Frage: welche Codierung des Server zu verwenden, da es nicht zu raten ist, muss es einen Parameterwert sein?), und wenn die Zeichenfolge codiert worden sind, eine andere Codierung Dzing , erhalten Daten beschädigt.

Es ist ganz ähnlich wie in Python zu tun:

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

Probieren Sie es aus. Es macht Spaß. Der decodierte Zeichenfolge sein soll „Hey, mein Name ist André“, ist aber „Hey, mein Name ist Andr テ ゥ“. é wird von der japanischen テ ersetzt ゥ

Daher mein Vorschlag: Sie müssen diese Pyodbc, um sicherzustellen, ist in der Lage die Daten direkt als Unicode zu senden. Wenn Pyodbc dies nicht tut, werden Sie unerwartete Ergebnisse erhalten.

Und ich beschrieben, das Problem in der Client-Server Art und Weise. Aber die gleiche Art von Problemen kann auftreten, wenn wieder vom Server an den Client zu kommunizieren. Wenn der Kunde nicht Unicode-Daten verstehen kann, werden Sie wahrscheinlich in Schwierigkeiten bekommen.

FreeTDS behandelt Unicode für Sie.

Eigentlich nimmt FreeTDS Pflege der Dinge für Sie und übersetzt alle Daten zu UCS2 Unicode. ( Quelle ).

  • Server <-> FreeTDS: UCS2 Daten
  • FreeTDS <-> Pyodbc: kodierten Strings, codiert in UTF-8 (von /etc/freetds/freetds.conf)

Also ich würde Ihre Anwendung erwartet korrekt zu arbeiten, wenn Sie UTF-8-Daten Pyodbc passieren. In der Tat, da dies django-Pyodbc Ticket Staaten, django-Pyodbc kommuniziert in UTF-8 mit Pyodbc, so dass Sie sollten in Ordnung sein.

FreeTDS 0,82

Allerdings cramm0 sagt, dass FreeTDS 0,82 ist nicht vollständig bugfree, und dass es erhebliche Unterschiede zwischen 0,82 und die offiziellen gepatcht 0,82 Version, die gefunden werden kann, hier . Sie sollten wahrscheinlich die gepatchte FreeTDS versuchen mit


Edited : alte Daten entfernt, die nichts mit FreeTDS zu tun hatte, war aber nur relevant kommerzielle ODBC-Treiber easySoft-. Es tut uns Leid.

Andere Tipps

Ich verwende UCS-2 mit SQL Server zu kommunizieren, sie nicht UTF-8.

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

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

Nun binden Werte arbeiten für UTF-8 kodierten Strings in Ordnung. Der Treiber wandelt transparent zwischen der UCS-2 für die Speicherung auf dem Datenserver Seite verwendet, und den UTF-8-kodierten Strings gegeben zu / von dem Kunden entnommen.

Dies ist mit Pyodbc 2.0 unter Solaris 10 läuft 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 von der Testtabelle (I manuell in einem Bündel von Testdaten über Management Studio gestellt hatte)

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 in der Lage war direkt vom Management Studio von ‚Edit Top 200 Zeilen‘ Dialog in die Tabelle in einige in Unicode-Codepunkten zu setzen und die Hex-Ziffern für den Unicode-Codepunkt eingeben und dann mit Alt-X

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

Ich löste es durch freetds auf Version 0.91 aktualisieren.

Ich benutze Pyodbc 2.1.11. Ich hatte diese anwenden Patch, um es mit Unicode funktioniert, sonst war ich Fehler Speicherfehler gelegentlich zu bekommen.

Sind Sie sicher, dass es INSERT ist das Problem verursacht liest nicht? Es ist ein Fehler offen auf Pyodbc Problem beim Abrufen NTEXT und NVARCHAR Daten .

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top