7

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」という名前で作成された空のデータベースがあります。完全な権限を持つパスワード「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()

この時点まですべてが機能します。サーバーで SQLServer の Enterprise Manager を使用しましたが、新しいテーブルがそこにあります。ここで、テーブルにデータを挿入したいと思います。

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

上記のすべてのコードをここに1 つのファイルにまとめました。これにより、支援したい人が簡単にテストできるようになります。

質問は次のとおりです。

画像ファイルを mssql に挿入する Python コードが必要です。画像をクエリしてユーザーに表示したい。

mssql の列の型は気にしません。この例では " " 列タイプを使用してIMAGEいますが、元の状態で挿入したファイルのバイナリ データを取得する限り、任意のバイナリ/ブロブ タイプで使用できます。Vinay Sajip は、SQL SERVER 2000 でこれが推奨されるデータ型であると以下で述べています。

データはエラーなしで挿入されていますが、データを取得すると 4k しか返されません。(データは 4096 で切り捨てられます)。

どうすればそれを機能させることができますか?


編集: 以下の Vinay Sajip の回答は、フィールドで pyodbc.Binary を使用するためのヒントを与えてくれました。それに応じて質問を更新しました。ありがとうビナイ・サジプ!

Alex Martelli のコメントから、DATALENGTHMS SQL 関数を使用して、データが列に完全にロードされているかどうかをテストするというアイデアが得られました。ありがとうアレックス・マーテリ!

4

3 に答える 3

5

へー、懸賞金を差し上げた直後に解決策が分かった。

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
于 2009-07-02T11:20:33.863 に答える
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 画像をデータベースに挿入および取得できるようになりました (取得されたデータは、挿入されたデータと同じです)。

NBimageデータ型は非推奨でありvarbinary(max)、SQL Server の以降のバージョンで置き換えられます。ただし、新しい列タイプには、挿入/取得の同じロジックが適用されます。

于 2009-06-29T19:58:17.580 に答える
1

フィールドで同様の4096切り捨ての問題がありましたが、これで修正されましたが、これでも修正されました。TEXTSET TEXTSIZE 2147483647

import os
os.environ['TDSVER'] = '8.0'
于 2011-08-04T14:56:53.603 に答える