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

StackOverflow https://stackoverflow.com/questions/1060035

Вопрос

Я использую 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,)) но теперь я отредактировал вопрос, потому что, следуя приведенному ниже ответу Винай Саджип (СПАСИБО), я изменил его на:

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-тип, при условии, что я получаю двоичные данные для файла, который я вставил обратно, нетронутыми.Винай Саджип сказал ниже, что это предпочтительный тип данных для этого в SQL SERVER 2000.

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

Как я могу заставить это работать?


ПРАВКИ:Приведенный ниже ответ Винай Саджип дал мне подсказку использовать pyodbc.Binary в поле.Я соответствующим образом обновил вопрос.Спасибо, Винай Саджип!

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

Это было полезно?

Решение

Ха, сразу после того, как я предложил награду, я нашел решение.

Вы должны использовать 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 размером 320 Кб в базу данных (извлеченные данные идентичны вставленным данным).

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

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

import os
os.environ['TDSVER'] = '8.0'
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top