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
python2.6-dev

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
    text size = 4294967295

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 vollen Privilegien.

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(odbcstring)
cur = con.cursor()

cur.execute("""
IF EXISTS(SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES
      WHERE TABLE_NAME = 'testing')
   DROP TABLE testing
""")
cur.execute('''
CREATE TABLE testing (
    id INTEGER NOT NULL IDENTITY(1,1), 
    myimage IMAGE 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()
# using web data for exact reproduction of the error by all.
# I'm actually reading a local file in my real code.
url = 'http://www.forestwander.com/wp-content/original/2009_02/west-virginia-mountains.jpg'
data = urllib2.urlopen(url).read()

sql = "INSERT INTO testing (myimage) VALUES (?)"

Jetzt ist hier auf meiner ursprünglichen Frage, ich habe Probleme cur.execute(sql, (data,)) verwenden, aber jetzt habe ich die Frage bearbeitet, weil folgende Vinay Sajip Antwort unten (DANKE), habe ich geändert habe es an:

cur.execute(sql, (pyodbc.Binary(data),)) 
con.commit()

Und Einfügen funktioniert perfekt . Ich kann die Größe der eingefügten Daten mit dem folgenden Testcode bestätigen:

cur.execute('SELECT DATALENGTH(myimage) FROM testing WHERE id = 1')
data_inside = cur.fetchone()[0]
assert data_inside == len(data)

Was passiert perfekt !!!

Das Problem ist jetzt auf Abruf der Daten zurück.

Ich versuche, den gemeinsamen Ansatz:

cur.execute('SELECT myimage FROM testing WHERE id = 1')
result = cur.fetchone()
returned_data = str(result[0]) # transforming buffer object
print 'Original: %d; Returned: %d' % (len(data), len(returned_data))
assert data == returned_data

Wie der auch nicht !!

Original: 4744611; Returned: 4096
Traceback (most recent call last):
  File "/home/nosklo/devel/teste_mssql_pyodbc_unicode.py", line 53, in <module>
    assert data == returned_data
AssertionError

Ich habe alle den Code in einer einzigen Datei setzen hier , für einfache Prüfung von jemandem, der helfen will.

Nun zur Frage:

Ich möchte Code Python eine Bilddatei in mssql einzufügen. Ich möchte das Bild abfragen zurück und zeigen Sie es an den Benutzer.

Ich kümmere mich nicht um die Säule MSSQL-Typen. Ich bin mit dem „IMAGE“ Spaltentyp am Beispiel, aber jeder binärer / Blob-Typ tun würde, solange ich die binären Daten für die Datei mich wieder unberührten eingefügt bekommen. Vinay Sajip unterhalb, dass dies der bevorzugte Datentyp für diesen in SQL Server 2000.

Die Daten werden jetzt ohne Fehler eingefügt, aber wenn ich die Daten abrufen, nur 4k zurückgegeben. (Die Daten werden auf 4096 gekürzt).

Wie kann ich diese Arbeit machen?


EDITS : Vinay Sajip Antwort unten gab mir einen Hinweis pyodbc.Binary auf dem Feld zu verwenden. Ich habe die Frage entsprechend aktualisiert. Dank Vinay Sajip!

Alex Martelli Kommentar gab mir die Idee, die DATALENGTH MS SQL-Funktion verwenden zu testen, ob die Daten vollständig auf die Säule geladen wird. Dank Alex Martelli!

War es hilfreich?

Lösung

Huh, kurz nach der Prämie anbieten, ich habe die Lösung gefunden werden.

Sie haben SET TEXTSIZE 2147483647 zu verwenden, auf der Abfrage, zusätzlich von Konfigurationsoption Textgröße in /etc/freetds/freetds.conf.

Ich habe verwendet

cur.execute('SET TEXTSIZE 2147483647 SELECT myimage FROM testing WHERE id = 1')

Und alles hat gut funktioniert.

Seltsame ist, was FreeTDS Dokumentation sagt über die Textgröße Konfigurationsoption:

  

Standardwert von TEXTSIZE in Bytes. Für text image und Datentypen, legt die maximale Breite jeder Säule zurückgeführt. Vgl set TEXTSIZE in der T-SQL Dokumentation für Ihren Server.

Die Konfiguration sagt auch, dass der Maximalwert (und die Standardeinstellung) 4294967295 ist. Allerdings, wenn Sie diesen Wert in der Abfrage zu verwenden, ich versucht, einen Fehler, die maximale Zahl, die ich in der Abfrage verwenden könnte, ist 2147483647 (die Hälfte).

Von dieser Erklärung, die ich dachte, dass nur diese Konfigurationsoption Einstellung wäre genug. Es stellt sich heraus, dass ich falsch war, TEXTSIZE in der Abfrage das Problem behoben zu setzen.

Im Folgenden finden Sie die komplette Arbeits Code:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import pyodbc
import urllib2

odbcstring = "SERVER=10.32.42.69;UID=sa;PWD=secret;DATABASE=Common;DRIVER=FreeTDS"
con = pyodbc.connect(odbcstring)
cur = con.cursor()

cur.execute("""
IF EXISTS(SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES
      WHERE TABLE_NAME = 'testing')
   DROP TABLE testing
""")

cur.execute('''
CREATE TABLE testing (
    id INTEGER NOT NULL IDENTITY(1,1), 
    myimage IMAGE NULL,
    PRIMARY KEY (id)
)
    ''')

con.commit()
cur = con.cursor()
url = 'http://www.forestwander.com/wp-content/original/2009_02/west-virginia-mountains.jpg'
data = urllib2.urlopen(url).read()

sql = "INSERT INTO testing (myimage) VALUES (?)"
cur.execute(sql, (pyodbc.Binary(data),))
con.commit()

cur.execute('SELECT DATALENGTH(myimage) FROM testing WHERE id = 1')
data_inside = cur.fetchone()[0]
assert data_inside == len(data)

cur.execute('SET TEXTSIZE 2147483647 SELECT myimage FROM testing WHERE id = 1')
result = cur.fetchone()
returned_data = str(result[0])
print 'Original: %d; Returned; %d' % (len(data), len(returned_data))
assert data == returned_data

Andere Tipps

Ich glaube, Sie sollten eine pyodbc.Binary Beispiel werden unter Verwendung der Daten zu wickeln:

cur.execute('INSERT INTO testing (myimage) VALUES (?)', (pyodbc.Binary(data),))

Apportieren sollte

cur.execute('SELECT myimage FROM testing')
print "image bytes: %r" % str(cur.fetchall()[0][0])

UPDATE: Das Problem bei der Insertion ist. Ändern Sie Ihre Einfügung SQL auf die folgenden:

"""DECLARE @txtptr varbinary(16)

INSERT INTO testing (myimage) VALUES ('')
SELECT @txtptr = TEXTPTR(myimage) FROM testing 
WRITETEXT testing.myimage @txtptr ?
"""

Ich habe auch den Fehler, aktualisiert ich bei der Verwendung der Wertattribut in dem Abrufcode gemacht.

Mit dieser Änderung, ich bin die Lage, ein 320K JPEG-Bildes in die Datenbank (abgerufenen Daten sind identisch mit eingefügten Daten).

einfügen und abrufen

N. B. Der image Datentyp ist veraltet und wird von varbinary(max) in späteren Versionen von SQL Server ersetzt. Die gleiche Logik zum Einsetzen / Retrieval gilt jedoch für den neueren Spaltentyp.

Ich hatte ein ähnliches 4096 Abschneiden Problem auf TEXT Feldern, die für mich fixiert SET TEXTSIZE 2147483647, aber das es auch für mich festgelegt:

import os
os.environ['TDSVER'] = '8.0'
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top