我正在使用 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
我从31e2fae4adbf1b2af1726e5668a3414cf46b454f
抓取了pyodbc修订版http://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()
到目前为止一切工作。我在服务器上使用过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
我已将上面的所有代码放在一个文件here中,以方便测试任何想要帮助的人。
现在提出问题:
我想让python代码将图像文件插入到mssql中。我想要查询图像并将其显示给用户。
我不关心mssql中的列类型。我在示例中使用“IMAGE
”列类型,但任何二进制/ blob类型都可以,只要我获取未插入的文件的二进制数据。 Vinay Sajip在下面说,这是SQL SERVER 2000中首选的数据类型。
现在插入的数据没有错误,但是当我检索数据时,只返回4k。 (数据在4096上被截断)。
我该如何做到这一点?
编辑:下面的Vinay Sajip回答给了我一个在场上使用pyodbc.Binary的提示。我已相应更新了这个问题。谢谢Vinay Sajip!
Alex Martelli的评论让我想到了使用DATALENGTH
MS SQL函数来测试数据是否在列上完全加载。谢谢Alex Martelli!
答案 0 :(得分:5)
除SET TEXTSIZE 2147483647
中的文字大小配置选项外,您还必须在查询中使用/etc/freetds/freetds.conf
。
我用过
cur.execute('SET TEXTSIZE 2147483647 SELECT myimage FROM testing WHERE id = 1')
一切正常。
Strange是关于文本大小配置选项的FreeTDS documentation says:
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
答案 1 :(得分: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])
更新:问题在于插入。将插入SQL更改为以下内容:
"""DECLARE @txtptr varbinary(16)
INSERT INTO testing (myimage) VALUES ('')
SELECT @txtptr = TEXTPTR(myimage) FROM testing
WRITETEXT testing.myimage @txtptr ?
"""
我还更新了在检索代码中使用value属性时犯的错误。
通过此更改,我可以将320K JPEG图像插入并检索到数据库中(检索的数据与插入的数据相同)。
N.B。不推荐使用image
数据类型,在SQL Server的更高版本中,varbinary(max)
将替换为{{1}}。但是,对于较新的列类型,插入/检索的逻辑应该适用。
答案 2 :(得分:1)
我在4096
字段上遇到类似的TEXT
截断问题,SET TEXTSIZE 2147483647
为我修复了问题,但这也为我解决了问题:
import os
os.environ['TDSVER'] = '8.0'