Pregunta

Estoy usando Ubuntu 9.04

He instalado las siguientes versiones de los paquetes:

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

He configurado el /etc/unixodbc.ini como este:

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

He configurado el /etc/freetds/freetds.conf como este:

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

Me han acaparado la pyodbc revisión 31e2fae4adbf1b2af1726e5668a3414cf46b454f de http://github.com/mkleehammer/pyodbc y instalado usando "python setup.py install"

Tengo una máquina con windows Microsoft SQL Server 2000 instalado en mi red local, y a la escucha en el local de la dirección ip 10.32.42.69.Tengo una base de datos vacía creado con el nombre "Común".Tengo el usuario "sa" con la contraseña "secreto" con todos los privilegios.

Estoy usando el siguiente código en python para la instalación de la conexión:

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

Todo OBRAS hasta este punto.He utilizado sql server Enterprise Manager en el servidor y la nueva tabla es la que hay.Ahora quiero insertar algunos datos en la tabla.

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

Ahora aquí en mi pregunta original, yo estaba teniendo problemas con el uso de cur.execute(sql, (data,)) pero ahora he editado la pregunta, porque a Vinay Sajip la respuesta de abajo (GRACIAS), he cambiado a:

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

Y la inserción funciona a la perfección.Puedo confirmar que el tamaño de los datos introducidos mediante el siguiente código de prueba:

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

Que pasa perfectamente!!!

Ahora el problema es en la recuperación de los datos.

Estoy intentando el enfoque común:

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

Sin embargo, de que no!!

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

He puesto todo el código anterior en un solo archivo aquí, para facilitar las pruebas de cualquier persona que quiere ayudar.

Ahora la pregunta:

Quiero el código de python para insertar un archivo de imagen en mssql.Quiero consultar de nuevo la imagen y mostrarla al usuario.

No me importa el tipo de columna en mssql.Estoy usando el "IMAGE"tipo de columna en el ejemplo, pero cualquier binario/tipo blob haría, siempre y cuando llego el binario de datos para el archivo que volver a introducir virgen.Vinay Sajip dijo a continuación que este es el tipo de datos preferido para esto en SQL SERVER 2000.

Los datos que ahora se inserta sin errores, sin embargo cuando puedo recuperar los datos, sólo los 4k son devueltos.(Los datos se truncan en 4096).

Cómo puedo hacer para que funcione?


EDICIONES:Vinay Sajip la respuesta de abajo me dio una pista para el uso pyodbc.Binario en el campo.He actualizado la pregunta en consecuencia.Gracias Vinay Sajip!

Alex Martelli comentario me dio la idea de utilizar el DATALENGTH MS SQL función para probar si los datos son totalmente cargado en la columna.Gracias Alex Martelli !

¿Fue útil?

Solución

Eh, sólo después de ofrecer la recompensa, he encontrado la solución.

Usted tiene que usar SET TEXTSIZE 2147483647 en la consulta, además de tamaño de texto de la opción de configuración en /etc/freetds/freetds.conf.

He utilizado

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

Y todo funcionó bien.

Extraño es lo que FreeTDS documentación dice sobre el tamaño del texto de la opción de configuración:

valor predeterminado de TEXTSIZE, en bytes.Para text y image tipos de datos, establece el ancho máximo de la devolución de la columna.Cf. set TEXTSIZE en el T-SQL documentación de su servidor.

La configuración también se dice que el valor máximo (el valor predeterminado) es 4,294,967,295.Sin embargo cuando se trata de utilizar ese valor en la consulta me sale un error, el número máximo que podría utilizar en la consulta es 2.147.483.647 (la mitad).

A partir de esa explicación que yo pensaba que sólo la configuración de esta opción de configuración sería suficiente.Resulta que yo estaba equivocado, la configuración de TEXTSIZE en la consulta se ha solucionado el problema.

Abajo es el completo código de trabajo:

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

Otros consejos

Creo que usted debe utilizar un pyodbc.Binary ejemplo para envolver los datos:

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

Recuperación debe ser

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

UPDATE: El problema está en la inserción. Cambiar su SQL de inserción a la siguiente:

"""DECLARE @txtptr varbinary(16)

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

También he actualizado el error que hice en el uso del atributo de valor en el código de recuperación.

Con este cambio, soy capaz de insertar y recuperar una imagen de 320K JPEG en la base de datos (datos recuperados es idéntico a los datos insertados).

N.B. El image tipo de datos está en desuso, y se sustituye por varbinary(max) en versiones posteriores de SQL Server. La misma lógica para la inserción / debería aplicarse de recuperación, sin embargo, para el tipo de columna más reciente.

Yo tenía un problema de truncamiento similares 4096 en TEXT campos, que SET TEXTSIZE 2147483647 fijos para mí, pero esto también lo arreglaron para mí:

import os
os.environ['TDSVER'] = '8.0'
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top