использование pyodbc на ubuntu для вставки поля изображения на SQL Server

я использую Ubuntu 9.04

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

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"

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

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

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

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

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,)) но теперь я отредактировал вопрос, потому что после ответа Vinay 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

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

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

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

меня не волнует колонка типа в MSSQL. Я использую "IMAGE " тип столбца в Примере, но любой двоичный / blob-тип будет делать, пока я получаю двоичные данные для файла, который я вставил обратно неиспорченным. Vinay Sajip сказал ниже, что это предпочтительный тип данных для этого в SQL SERVER 2000.

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

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


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

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

3 ответов


ха, сразу после предложения награды, я нашел решение.

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

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

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

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

странно то, что документация FreeTDS говорит о опции конфигурации размера текста:

значение по умолчанию TEXTSIZE в байтах. Для text и image типы данных, задает максимальную ширину любого возвращаемого столбца. Ср. set TEXTSIZE на T-SQL документация для вашего сервера.

конфигурация также говорит, что максимальное значение (по умолчанию) является 4,294,967,295. Однако при попытке использовать это значение в запросе я получаю ошибку, максимальное число, которое я мог бы использовать в запросе, - 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

Я думаю, вы должны использовать 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])

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

"""DECLARE @txtptr varbinary(16)

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

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

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

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


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

import os
os.environ['TDSVER'] = '8.0'