2009-06-29 35 views
7

Tôi đang sử dụng Ubuntu 9,04sử dụng pyodbc trên ubuntu để chèn một lĩnh vực hình ảnh trên SQL Server

Tôi đã cài đặt các phiên bản gói sau:

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 

Tôi đã cấu hình /etc/unixodbc.ini như thế này:

[FreeTDS] 
Description    = TDS driver (Sybase/MS SQL) 
Driver   = /usr/lib/odbc/libtdsodbc.so 
Setup   = /usr/lib/odbc/libtdsS.so 
CPTimeout    = 
CPReuse   = 
UsageCount    = 2 

Tôi đã định cấu hình /etc/freetds/freetds.conf như sau:

[global] 
    tds version = 8.0 
    client charset = UTF-8 
    text size = 4294967295 

Tôi đã chộp lấy pyodbc sửa đổi 31e2fae4adbf1b2af1726e5668a3414cf46b454f từ http://github.com/mkleehammer/pyodbc và cài đặt nó sử dụng "python setup.py install"

Tôi có một máy cửa sổ với Microsoft SQL Server 2000 cài đặt trên mạng nội bộ của tôi, và lắng nghe trên ip địa phương địa chỉ 10.32.42.69. Tôi có một cơ sở dữ liệu rỗng được tạo với tên "Chung". Tôi có người dùng "sa" với mật khẩu "bí mật" với đầy đủ đặc quyền.

Tôi đang sử dụng mã python sau để thiết lập kết nối:

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

Tất cả mọi thứ TRÌNH đến thời điểm này. Tôi đã sử dụng Enterprise Manager của SQLServer trên máy chủ và bảng mới là ở đó. Bây giờ tôi muốn chèn một số dữ liệu trên bảng.

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

Bây giờ ở đây về câu hỏi ban đầu của tôi, tôi đã gặp khó khăn trong sử dụng cur.execute(sql, (data,)) nhưng bây giờ tôi đã chỉnh sửa câu hỏi, bởi vì sau câu trả lời Vinay Sajip của bên dưới (THANKS), tôi đã thay đổi nó để:

cur.execute(sql, (pyodbc.Binary(data),)) 
con.commit() 

Và chèn hoạt động hoàn hảo. Tôi có thể khẳng định kích thước của dữ liệu được chèn bằng cách sử dụng mã kiểm tra sau:

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

nào đi hoàn hảo !!!

Hiện tại, sự cố đang được khôi phục dữ liệu.

tôi đang cố gắng tiếp cận chung:

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 

Tuy nhiên thất bại !!

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 

Tôi đã đặt tất cả mã ở trên vào một tệp here, để dễ dàng kiểm tra bất kỳ ai muốn trợ giúp.

Bây giờ cho câu hỏi:

Tôi muốn mã python chèn tệp hình ảnh vào mssql. Tôi muốn truy vấn lại hình ảnh và hiển thị nó cho người dùng.

Tôi không quan tâm đến loại cột trong mssql.Tôi đang sử dụng loại cột "IMAGE" trên ví dụ, nhưng bất kỳ loại nhị phân/blob nào sẽ làm, miễn là tôi nhận được dữ liệu nhị phân cho tệp mà tôi đã chèn trở lại không bị hỏng. Vinay Sajip nói dưới đây rằng đây là kiểu dữ liệu ưa thích cho điều này trong SQL SERVER 2000.

Dữ liệu hiện đang được chèn mà không có lỗi, tuy nhiên khi tôi lấy dữ liệu, chỉ 4k được trả về. (Dữ liệu được cắt ngắn trên 4096).

Tôi làm cách nào để làm việc đó?


CÁC CHỈNH SỬA: Câu trả lời Vinay Sajip của dưới đây đã cho tôi một gợi ý để sử dụng pyodbc.Binary trên sân. Tôi đã cập nhật câu hỏi cho phù hợp. Cảm ơn Vinay Sajip!

Nhận xét của Alex Martelli đã cho tôi ý tưởng sử dụng hàm MS SQL DATALENGTH để kiểm tra xem dữ liệu có được tải đầy đủ trên cột hay không. Cảm ơn Alex Martelli!

+0

gì thế nào bạn nhận được khi bạn 'SELECT DATALENGTH (myimage) FROM testing'? Ít nhất điều này sẽ cho bạn biết nếu vấn đề của bạn là với lưu trữ hoặc với lấy. –

Trả lời

5

Huh, ngay sau khi cung cấp tiền thưởng, tôi đã tìm ra giải pháp.

Bạn phải sử dụng SET TEXTSIZE 2147483647 trên truy vấn, ngoài tùy chọn cấu hình kích thước văn bản trong /etc/freetds/freetds.conf.

Tôi đã sử dụng

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

Và tất cả mọi thứ làm việc tốt.

Strange là những gì FreeTDS documentation says về văn bản tùy chọn cấu hình kích thước:

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.

Cấu hình cũng nói rằng giá trị lớn nhất (và mặc định) là 4294967295. Tuy nhiên khi cố gắng sử dụng giá trị đó trong truy vấn tôi nhận được một lỗi, số lượng tối đa tôi có thể sử dụng trong truy vấn là 2.147.483.647 (một nửa).

Từ giải thích đó, tôi nghĩ rằng chỉ thiết lập tùy chọn cấu hình này là đủ. Nó chỉ ra rằng tôi đã sai, thiết lập TEXTSIZE trong truy vấn cố định vấn đề.

Dưới đây là đoạn code làm việc hoàn chỉnh:

#!/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

Tôi nghĩ rằng bạn nên sử dụng một trường hợp pyodbc.Binary để bọc các dữ liệu:

cur.execute('INSERT INTO testing (myimage) VALUES (?)', (pyodbc.Binary(data),)) 

lấy nên

cur.execute('SELECT myimage FROM testing') 
print "image bytes: %r" % str(cur.fetchall()[0][0]) 

UPDATE: Vấn đề là trong chèn. Thay đổi SQL chèn của bạn thành:

"""DECLARE @txtptr varbinary(16) 

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

Tôi cũng đã cập nhật lỗi mà tôi đã thực hiện khi sử dụng thuộc tính giá trị trong mã truy xuất.

Với thay đổi này, tôi có thể chèn và truy xuất hình ảnh JPEG 320K vào cơ sở dữ liệu (dữ liệu đã truy xuất giống hệt với dữ liệu được chèn).

N.B. Loại dữ liệu image không còn được dùng nữa và được thay thế bằng varbinary(max) trong các phiên bản sau của SQL Server. Tuy nhiên, cùng một logic để chèn/truy xuất nên áp dụng cho loại cột mới hơn.

+0

Đúng, mặc dù tôi đã phải sử dụng str (cur.fetchall() [0] [0]) để lấy dữ liệu. .value trả về: AttributeError: đối tượng 'buffer' không có thuộc tính 'value' – nosklo

+0

Tôi vẫn gặp sự cố. Tôi đã cập nhật câu hỏi, xin hãy xem. – nosklo

+0

Thans Vinay để cập nhật. Hóa ra vấn đề không được đưa vào. Tôi đã thử mã TEXTPTR và nhận được kết quả tương tự. Cảm ơn vì đã dành thời gian cho tôi. Tôi đã chỉnh sửa lại câu hỏi để hiển thị vấn đề hiện tại. Bạn có thể cho tôi mã đầy đủ mà bạn đã nói là đã làm việc không? Bạn có thể cho tôi biết chi tiết về thiết lập của bạn không? Tôi vẫn không thể làm cho nó hoạt động được. Nếu nó không đòi hỏi nhiều, bạn có thể vui lòng chạy mã của tôi không thay đổi trên thiết lập của bạn và cho tôi biết kết quả không? Tôi đã làm cho nó có sẵn trên http://paste.pocoo.org/show/125955/ và nó sử dụng một tập tin trên internet để nó sẽ chạy chính xác như nhau. – nosklo

1

Tôi đã có một vấn đề 4096 cắt ngắn tương tự trên TEXT lĩnh vực, trong đó SET TEXTSIZE 2147483647 cố định đối với tôi, nhưng điều này cũng cố định nó cho tôi:

import os 
os.environ['TDSVER'] = '8.0' 
Các vấn đề liên quan