2009-06-29 1 views
7

Я использую Ubuntu 9,04с помощью pyodbc на убунту, чтобы вставить поле изображения на SQL Server

Я установил следующие версии пакета:

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 

Я настроен /etc/unixodbc.ini так:

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

У меня есть /etc/freetds/freetds.conf вот так:

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

Я схватил pyodbc ревизию 31e2fae4adbf1b2af1726e5668a3414cf46b454f из http://github.com/mkleehammer/pyodbc и установил его с помощью «python setup.py install»

У меня есть машина окна с Microsoft SQL Server 2000 установлен на моей локальной сети, и слушать на локальном IP адрес 10.32.42.69. У меня есть пустая база данных, созданная с именем «Common». У меня есть пользователь «sa» с паролем «секретный» с полными привилегиями.

Я использую следующий код питона для установки соединения:

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

Все, WORKS до этого момента. Я использовал SQL Server Server Enterprise Manager на сервере, и там есть новая таблица. Теперь я хочу вставить некоторые данные в таблицу.

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

Теперь вот на мой первоначальный вопрос, у меня была проблема с использованием cur.execute(sql, (data,)), но теперь я редактировал вопрос, потому что следующий ответ Вине Sajip в ниже (спасибо), я изменил его:

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

Однако это терпит неудачу !!

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 

Я поместил весь код выше в одном файле here, для простого тестирования тех, кто хочет помочь.

Теперь вопрос:

Я хочу питон код для вставки файла изображения в MSSQL. Я хочу запросить изображение и показать его пользователю.

Мне не нужен тип столбца в mssql.Я использую в столбце тип столбца «», но любой тип двоичного/блочного будет делать, пока я получаю двоичные данные для файла, который я вставлял обратно в нетронутый. Vinay Sajip сказал ниже, что это предпочтительный тип данных для этого в SQL SERVER 2000.

Данные теперь вставляются без ошибок, однако при получении данных возвращаются только 4k. (Данные усекаются на 4096).

Как я могу сделать эту работу?


редактирует: ответ Вины Sajip в ниже дал мне подсказку использовать pyodbc.Binary на поле. Я соответствующим образом обновил этот вопрос. Спасибо Vinay Sajip!

Комментарий Alex Martelli дал мне идею использования функции MS SQL DATALENGTH, чтобы проверить, полностью ли загружены данные в столбце. Спасибо, Алекс Мартелли!

+0

, что вы получаете, когда выбрали «ВЫБРАТЬ ДАТУЛИРОВАНИЕ (myimage) FROM testing»? По крайней мере, это скажет вам, есть ли проблема с сохранением или извлечением. –

ответ

5

Да, сразу после предлагая щедрость, я нашел решение.

Вы должны использовать SET TEXTSIZE 2147483647 по запросу, в дополнение к опции конфигурации размера текста в /etc/freetds/freetds.conf.

Я использовал

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

И все работало нормально.

Странно то, что FreeTDS documentation says о возможности конфигурации размера текста:

default value of TEXTSIZE , in bytes. For text and image datatypes, sets the maximum width of any returned column. Cf. set TEXTSIZE in the T-SQL documentation for your server.

Конфигурация также говорит о том, что максимальное значение (значение по умолчанию) является 4294967295. Однако при попытке использовать это значение в запросе я получаю сообщение об ошибке, максимальное число, которое я мог бы использовать в запросе, составляет 2 147 483 647 (половина).

Из этого объяснения я думал, что достаточно установить этот вариант конфигурации. Оказывается, я ошибся, установив TEXTSIZE в запросе, исправил проблему.

Ниже приводится полный рабочий код:

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

Я думаю, вы должны использовать pyodbc.Binary экземпляр, чтобы обернуть данные:

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

Получение должно быть

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

UPDATE: Проблема заключается в введении. Изменение вставки SQL на следующее:

"""DECLARE @txtptr varbinary(16) 

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

Я также обновил ошибку, которую я сделал при помощи атрибута значения в коде извлечения.

С этим изменением я могу вставить и извлечь изображение 320K JPEG в базу данных (полученные данные идентичны вставленным данным).

N.B. Тип данных image устарел и заменяется varbinary(max) в более поздних версиях SQL Server. Тем не менее, для новой версии столбца должна применяться одна и та же логика для вставки/извлечения.

+0

Правильно, хотя мне пришлось использовать str (cur.fetchall() [0] [0]) для получения данных. .value return: AttributeError: объект «buffer» не имеет атрибута «значение» – nosklo

+0

У меня все еще возникают проблемы. Я обновил вопрос, пожалуйста, взгляните. – nosklo

+0

Thans Vinay для обновления. Оказывается, проблема не в установке. Я пробовал код TEXTPTR и получил тот же результат. Спасибо за ваше время. Я снова редактировал этот вопрос, чтобы показать текущую проблему. Можете ли вы дать мне полный код, который вы сказали, который сработал? Можете ли вы рассказать мне о своей настройке? Я все еще не могу заставить его работать. Если он не просит многого, можете ли вы также запустить мой код без изменений в настройках и сообщить мне результаты? Я сделал его доступным на http://paste.pocoo.org/show/125955/, и он использует файл в Интернете, поэтому он будет работать точно так же. – nosklo

1

У меня была аналогичная проблема 4096 усечения на TEXT полях, SET TEXTSIZE 2147483647 фиксированной для меня, но это также установил ее для меня:

import os 
os.environ['TDSVER'] = '8.0' 
Смежные вопросы