using pyodbc on ubuntu to insert a image field on SQL Server
2015-01-12 19:05
2061 查看
using
pyodbc on ubuntu to insert a image field on SQL Server
up vote6down votefavorite 8 | I am using Ubuntu 9.04 I have installed the following package versions: 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 I have configured /etc/unixodbc.inilike this: [FreeTDS] Description = TDS driver (Sybase/MS SQL) Driver = /usr/lib/odbc/libtdsodbc.so Setup = /usr/lib/odbc/libtdsS.so CPTimeout = CPReuse = UsageCount = 2 I have configured /etc/freetds/freetds.conflike this: [global] tds version = 8.0 client charset = UTF-8 text size = 4294967295 I have grabbed pyodbc revision 31e2fae4adbf1b2af1726e5668a3414cf46b454ffrom http://github.com/mkleehammer/pyodbcand installed it using " python setup.py install" I have a windows machine with Microsoft SQL Server 2000 installed on my local network, up and listening on the local ip address 10.32.42.69. I have an empty database created with name "Common". I have the user "sa" with password "secret" with full privileges. I am using the following python code to setup the connection: 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() Everything WORKS up to this point. I have used SQLServer's Enterprise Manager on the server and the new table is there. Now I want to insert some data on the table. 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 (?)" Now here on my original question, I was having trouble using cur.execute(sql, (data,))but now I've edited the question, because following Vinay Sajip's answer below (THANKS), I have changed it to: cur.execute(sql, (pyodbc.Binary(data),)) con.commit() And insertion is working perfectly. I can confirm the size of the inserted data using the following test code: cur.execute('SELECT DATALENGTH(myimage) FROM testing WHERE id = 1') data_inside = cur.fetchone()[0] assert data_inside == len(data) Which passes perfectly!!! Now the problem is on retrieval of the data back. I am trying the common approach: 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 However that fails!! 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 I've put all the code above in a single file here, for easy testing of anyone that wants to help. Now for the question: I want python code to insert an image file into mssql. I want to query the image back and show it to the user. I don't care about the column type in mssql. I am using the " IMAGE" column type on the example, but any binary/blob type would do, as long as I get the binary data for the file I inserted back unspoiled. Vinay Sajip said below that this is the preferred data type for this in SQL SERVER 2000. The data is now being inserted without errors, however when I retrieve the data, only 4k are returned. (Data is truncated on 4096). How can I make that work? EDITS: Vinay Sajip's answer below gave me a hint to use pyodbc.Binary on the field. I have updated the question accordingly. Thanks Vinay Sajip! Alex Martelli's comment gave me the idea of using the DATALENGTHMS SQL function to test if the data is fully loaded on the column. Thanks Alex Martelli ! python sql-server image pyodbc freetds
| ||||
a comment |
4 Answers
activeoldestvotesup vote3down voteaccepted | Huh, just after offering the bounty, I've found out the solution. You have to use SET TEXTSIZE 2147483647on the query, in addition of text size configuration option in /etc/freetds/freetds.conf. I have used cur.execute('SET TEXTSIZE 2147483647 SELECT myimage FROM testing WHERE id = 1') And everything worked fine. Strange is what FreeTDS documentation says about the text size configuration option: default value of TEXTSIZE, in bytes. For textand imagedatatypes, sets the maximum width of any returned column. Cf. set TEXTSIZEin the T-SQLdocumentation for your server. The configuration also says that the maximum value (and the default) is 4,294,967,295. However when trying to use that value in the query I get an error, the max number I could use in the query is 2,147,483,647 (half). From that explanation I thought that only setting this configuration option would be enough. It turns out that I was wrong, setting TEXTSIZE in the query fixed the issue. Below is the complete working code: #!/usr/bin/env python
| ||
add a comment |
up vote2down vote | I think you should be using a pyodbc.Binaryinstance to wrap the data: cur.execute('INSERT INTO testing (myimage) VALUES (?)', (pyodbc.Binary(data),)) Retrieving should be cur.execute('SELECT myimage FROM testing') print "image bytes: %r" % str(cur.fetchall()[0][0]) UPDATE: The problem is in insertion. Change your insertion SQL to the following: """DECLARE @txtptr varbinary(16) INSERT INTO testing (myimage) VALUES ('') SELECT @txtptr = TEXTPTR(myimage) FROM testing WRITETEXT testing.myimage @txtptr ? """ I've also updated the mistake I made in using the value attribute in the retrieval code. With this change, I'm able to insert and retrieve a 320K JPEG image into the database (retrieved data is identical to inserted data). N.B. The imagedata type is deprecated, and is replaced by varbinary(max)in later versions of SQL Server. The same logic for insertion/retrieval should apply, however, for the newer column type.
| ||||||||||||||||
a comment |
up vote1down vote | SET TEXTSIZE 2147483647 Many thanks for post your solution. I was two hours searching the internet about this problem. :)
| ||
add a comment |
up vote1down vote | I had a similar 4096truncation issue on TEXTfields, which SET TEXTSIZE 2147483647fixed for me, but this also fixed it for me: import os os.environ['TDSVER'] = '8.0'
| ||
add a comment |
相关文章推荐
- Using SQLCMD to deploy sql script on SQLServer
- Using MERGE in SQL Server to insert, update and delete at the same time
- [转]How to find who is using / eating up the Virtual Address Space on your SQL Server
- Using pulseaudio to setup sound server on Ubuntu
- Using Visual Studio 2005 to Perform Load Testing on a SQL Server 2005 Reporting Services Report Server
- [SQL Server][FILESTREAM] -- Using INSERT, UPDATE and DELETE to manage SQL Server FILESTREAM Data
- using FFMPEG to setup HLS server on Ubuntu
- using sqlbulkcopy to quick load data from your client to sqlserver
- How to troubleshoot slow-running queries on SQL Server 7.0 or on later versions [ZT-from MS]
- How to check Fragmentation on SQL Server 2005
- a funtion to search using sqlserver search engine.
- Import data from files to SQL Server(用BULK INSERT命令导入数据详解)
- 海洋工作室——网站建设专家:How to check the SQL statement execute time on SQL Server ?
- CodeSnip: How to Get Id of the Record Using ASP.NET and SQL Server 2000
- How to check the MS SQL Server job run status by using Script
- Ruby On Rails Connection To MicroSoft SQL Server[Part 1]
- LotusScript Class to do client or server side FTP on Win32 platform. FTP using script and wininet.dll.
- Connecting to databases like Mysql, SQL Server or Oracle on J2ME devices
- Image To SQL Server
- Using the Microsoft Access Providers to Replace the Built-In SQL Server Providers