2009-06-29 41 views
7

我使用Ubuntu 9.04的使用pyodbc在Ubuntu上插入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 

我從http://github.com/mkleehammer/pyodbc抓住pyodbc修訂31e2fae4adbf1b2af1726e5668a3414cf46b454f並使用「python setup.py install

我有一個Windows機器的Microsoft SQL Server 2000安裝在我的本地網絡上,並監聽本地IP安裝地址10.32.42.69。我有一個名爲「Common」的空數據庫。我擁有帶密碼「secret」的用戶「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() 

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

現在在這裏我原來的問題,我遇到了麻煩,使用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,對於希望幫助人的簡單的測試。

現在的問題:

我想Python代碼插入圖像文件到MSSQL。我想查詢圖像並將其顯示給用戶。

我不關心mssql中的列類型。我在示例中使用的是「IMAGE」列類型,但只要我獲得未插入的文件的二進制數據,就可以使用任何二進制/ blob類型。 Vinay Sajip在下面說,這是SQL SERVER 2000中的首選數據類型。

現在插入的數據沒有錯誤,但是當我檢索數據時,只返回4k。 (數據在4096上被截斷)。

我該如何做這項工作?


編輯:下面的Vinay Sajip的回答給了我一個提示使用pyodbc.Binary在球場上。我已經相應地更新了這個問題。感謝Vinay Sajip!

Alex Martelli的評論讓我想到了使用MS SQL函數測試數據是否完全加載到列上的問題。感謝Alex Martelli!

+0

什麼當你'選擇DATALENGTH(myimage)從測試'時你會得到嗎?至少這會告訴你,如果你的問題是存儲或檢索。 – 2009-06-29 22:40:14

回答

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.

該配置還表示,最大值(和默認值)爲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 
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數據類型已被棄用,並在SQL Server的更高版本中被替換爲varbinary(max)。但是,插入/檢索的相同邏輯應適用於較新的列類型。

+0

正確,雖然我不得不使用str(cur.fetchall()[0] [0])來獲取數據。 .value返回:AttributeError:'buffer'對象沒有任何屬性'值' – nosklo 2009-06-29 20:18:38

1

我對TEXT領域,其中SET TEXTSIZE 2147483647固定對我來說是類似4096截斷的問題,但是這也固定爲我:

import os 
os.environ['TDSVER'] = '8.0' 
相關問題