باستخدام pyodbc على أوبونتو لإدراج صورة الميدانية على SQL Server

StackOverflow https://stackoverflow.com/questions/1060035

سؤال

أنا باستخدام أوبونتو 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

لقد أمسك pyodbc مراجعة 31e2fae4adbf1b2af1726e5668a3414cf46b454f من http://github.com/mkleehammer/pyodbc و تثبيته باستخدام "python setup.py install"

لدي جهاز ويندوز مع Microsoft SQL Server 2000 مثبت على الشبكة المحلية, و الاستماع على عنوان ip المحلي 10.32.42.69.لدي قاعدة بيانات فارغة تم إنشاؤها باستخدام اسم "مشترك".لدي المستخدم "sa" مع كلمة "سرية" مع كامل الامتيازات.

أنا باستخدام التالية كود بايثون لإعداد الاتصال:

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,)) ولكن الآن لقد تم تحريرها السؤال ، لأن التالية فيني 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

لقد وضع كل رمز أعلاه في ملف واحد هنا, لسهولة اختبار من أي شخص يريد المساعدة.

الآن السؤال:

أريد كود بايثون لإدراج صورة من ملف إلى mssql.أريد الاستعلام عن الصورة مرة أخرى و تظهر للمستخدم.

أنا لا يهمني نوع العمود في mssql.أنا باستخدام "IMAGE عمود " نوع على سبيل المثال ، ولكن أي ثنائي/blob نوع تفعل طالما يمكنني الحصول على البيانات الثنائية الملف إدخاله مرة أخرى البكر.فيني Sajip وقال أدناه أن هذا هو المفضل نوع البيانات في SQL SERVER 2000.

البيانات هو الآن يتم إدراجها دون أخطاء ، ولكن عند استرداد البيانات فقط 4k يتم إرجاعها.(البيانات يتم اقتطاع على 4096).

كيف يمكنني جعل هذا العمل ؟


التعديلات:فيني Sajip الجواب أدناه أعطاني إشارة إلى استخدام pyodbc.الثنائية في هذا المجال.لقد قمت بتحديث السؤال وفقا لذلك.شكرا فيني Sajip!

أليكس مارتيلي تعليق أعطاني فكرة استخدام DATALENGTH MS SQL وظيفة لاختبار إذا كانت البيانات التي يتم تحميلها بالكامل على العمود.شكرا اليكس مارتيلي !

هل كانت مفيدة؟

المحلول

صحيح, بعد تقدم فضله ، لقد وجدت الحل.

لديك لاستخدام 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 وثائق الملقم الخاص بك.

التكوين يقول أيضا أن القيمة القصوى (الافتراضي) 4294967295.ولكن عند محاولة استخدام هذه القيمة في الاستعلام أحصل على خطأ ، العدد الأقصى أتمكن من استخدامها في الاستعلام هو 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

نصائح أخرى

أعتقد أن عليك أن تكون باستخدام 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 ?
"""

لقد قمت بتحديث أيضا أخطأت في استخدام قيمة السمة في استرجاع رمز.

مع هذا التغيير ، أنا قادرة على إدراج واسترداد 320K صورة JPEG في قاعدة البيانات (استرجاع البيانات مطابقة إدخال البيانات).

N. B.على image نوع البيانات هو مستنكر ، يتم استبداله varbinary(max) في الإصدارات الأحدث من SQL Server.نفس المنطق الإدراج/استرجاع يجب أن ينطبق إلا على أحدث نوع العمود.

أنا 4096 اقتطاع المسألة على TEXT الحقول ، SET TEXTSIZE 2147483647 ثابت بالنسبة لي, ولكن هذا أيضا ثابتة بالنسبة لي:

import os
os.environ['TDSVER'] = '8.0'
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top