在ubuntu上使用pyodbc在SQL Server上插入图像字段

nos*_*klo 7 python sql-server image pyodbc freetds

我正在使用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
Run Code Online (Sandbox Code Playgroud)

我这样配置/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
Run Code Online (Sandbox Code Playgroud)

我这样配置/etc/freetds/freetds.conf:

[global]
    tds version = 8.0
    client charset = UTF-8
    text size = 4294967295
Run Code Online (Sandbox Code Playgroud)

我已经抓住pyodbc修订31e2fae4adbf1b2af1726e5668a3414cf46b454fhttp://github.com/mkleehammer/pyodbc,并使用安装了" python setup.py install"

我在我的本地网络上安装了一台安装了Microsoft SQL Server 2000的Windows机器,然后侦听本地IP地址10.32.42.69.我有一个名为"Common"的空数据库.我有用户"sa",密码为"secret",具有完全权限.

我使用以下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()
Run Code Online (Sandbox Code Playgroud)

一切WORKS了这一点.我在服务器上使用过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 (?)"
Run Code Online (Sandbox Code Playgroud)

现在在我原来的问题上,我在使用时遇到了麻烦,cur.execute(sql, (data,))但现在我编辑了这个问题,因为按照下面的Vinay Sajip的回答(谢谢),我把它改为:

cur.execute(sql, (pyodbc.Binary(data),)) 
con.commit()
Run Code Online (Sandbox Code Playgroud)

插入工作完美.我可以使用以下测试代码确认插入数据的大小:

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

完美传递!!!

现在的问题是回收数据.

我正在尝试常见的方法:

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
Run Code Online (Sandbox Code Playgroud)

然而,失败!!

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
Run Code Online (Sandbox Code Playgroud)

我已经把所有的代码上面的在一个文件在这里,对于希望帮助人的简单的测试.

现在提问:

我想要python代码将图像文件插入到mssql中.我想要查询图像并将其显示给用户.

我不关心mssql中的列类型.我IMAGE在示例中使用" "列类型,但任何二进制/ blob类型都可以,只要我获取未插入的文件的二进制数据.Vinay Sajip在下面说,这是SQL SERVER 2000中首选的数据类型.

现在插入的数据没有错误,但是当我检索数据时,只返回4k.(数据在4096上被截断).

我怎样才能做到这一点?


编辑:Vinay Sajip在下面的回答给了我一个暗示在场上使用pyodbc.Binary.我已相应更新了这个问题.谢谢Vinay Sajip!

Alex Martelli的评论让我想到了使用DATALENGTHMS SQL函数来测试数据是否在列上完全加载.谢谢Alex Martelli!

nos*_*klo 5

嗯,在提供赏金之后,我找到了解决方案.

SET TEXTSIZE 2147483647除了文本大小配置选项之外,您还必须在查询上使用/etc/freetds/freetds.conf.

我用过

cur.execute('SET TEXTSIZE 2147483647 SELECT myimage FROM testing WHERE id = 1')
Run Code Online (Sandbox Code Playgroud)

一切都很好.

奇怪的是FreeTDS文档所说的文本大小配置选项:

默认值TEXTSIZE,以字节为单位.对于textimage数据类型,设置任何返回列的最大宽度.参看 set TEXTSIZET-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
Run Code Online (Sandbox Code Playgroud)