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

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

Ho afferrato revisione pyodbc 31e2fae4adbf1b2af1726e5668a3414cf46b454f 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(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()

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()
# 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 (?)"

Ora qui sulla mia domanda iniziale, ho avuto problemi con l'uso cur.execute(sql, (data,)) ma ora ho curato la questione, perché in seguito la risposta di Vinay Sajip sotto (Grazie), ho cambiato a:

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

E 'inserimento è perfettamente funzionante . Posso confermare la dimensione dei dati inseriti utilizzando il seguente codice di prova:

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

che passa perfettamente !!!

Ora il problema è il recupero dei dati storici.

Sto cercando l'approccio comune:

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

Tuttavia, che non riesce !!

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

Ho messo tutto il codice di cui sopra in un unico file qui , per un facile test di qualcuno che vuole aiutare.

Ora per la domanda:

Voglio codice Python per inserire un file di immagine in mssql. Voglio interrogare l'immagine indietro e mostrare all'utente.

Non mi interessa circa il tipo di colonna in MSSQL. Sto usando il "IMAGE" tipo di colonna sull'esempio, ma qualsiasi / tipo blob binario farei, fino a quando ottengo i dati binari per il file ho inserito di nuovo incontaminata. Vinay Sajip detto di seguito che questo è il tipo di dati preferito per questo in SQL Server 2000.

I dati sono ora in fase di inserimento senza errori, ma quando posso recuperare i dati, vengono restituiti solo 4k. (I dati viene troncato sul 4096).

Come posso fare quel lavoro?


EDITS : la risposta di Vinay Sajip seguito mi ha dato un suggerimento per utilizzare pyodbc.Binary sul campo. Ho aggiornato la questione di conseguenza. Grazie Vinay Sajip!

Il commento di Alex Martelli mi ha dato l'idea di utilizzare la funzione di DATALENGTH MS SQL per verificare se i dati è a pieno carico sulla colonna. Grazie Alex Martelli!

È stato utile?

Soluzione

Eh, proprio dopo aver offerto la generosità, ho trovato la soluzione.

Devi usare SET TEXTSIZE 2147483647 sulla query, in aggiunta opzione di configurazione dimensione del testo in /etc/freetds/freetds.conf di.

ho usato

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

E tutto ha funzionato bene.

Strano è ciò documentazione FreeTDS dice sull'opzione di configurazione dimensione del testo:

  

valore predefinito di TEXTSIZE, in byte. Per text e image tipi di dati, imposta la larghezza massima di ogni colonna restituita. Cf. set TEXTSIZE nella documentazione T-SQL per il server.

La configurazione dice anche che il valore massimo (e il valore predefinito) è 4,294,967,295. Tuttavia quando si cerca di utilizzare tale valore nella query si ottiene un errore, il numero massimo potrei usare nella query è 2,147,483,647 (la metà).

Da questa spiegazione ho pensato che solo l'impostazione di questa opzione di configurazione sarebbe sufficiente. Si scopre che mi sbagliavo, impostando TEXTSIZE nella query risolto il problema.

Di seguito è riportato il codice di lavoro completo:

#!/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

Altri suggerimenti

Credo che si dovrebbe usare un pyodbc.Binary esempio per avvolgere i dati:

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

Recupero deve essere

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

UPDATE: Il problema è di inserimento. Cambia la tua SQL inserimento al seguente:

"""DECLARE @txtptr varbinary(16)

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

Ho anche aggiornato l'errore che ho fatto nella utilizzando l'attributo valore nel codice di recupero.

Con questa modifica, sono in grado di inserire e recuperare un'immagine JPEG 320K nella banca dati (dati recuperati è identica a dati inseriti).

NB. Il image tipo di dati è deprecato, e viene sostituito da varbinary(max) nelle versioni successive di SQL Server. La stessa logica per l'inserimento / recupero deve applicare, tuttavia, per il tipo di colonna nuova.

Ho avuto un simile problema 4096 troncamento su TEXT campi, che SET TEXTSIZE 2147483647 fissati per me, ma anche questo fissato per me:

import os
os.environ['TDSVER'] = '8.0'
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top