Python Sqlite3 将 BLOB 传递给用户定义的函数得到 None

Python Sqlite3 passing BLOB to user-defined function gives None

我试图将数据从 BLOB 列传递到用户定义的函数中,但它在该函数中显示为 None。这只是一个怪癖,还是我做错了什么?

BLOB 数据是我使用 Python 2.7.12 放入 sqlite3 数据库的 jpeg。 table 的架构是 CREATE TABLE data (md5sum TEXT PRIMARY KEY, data BLOB);


import sqlite3
import hashlib


def p_data(x):
    print [x]
    return x

def p_md(x):
    print [x]
    return x

db=sqlite3.connect('tagged.db')
db.text_factory = str

db.create_function('P_DATA', 1, p_data)
db.create_function('P_MD', 1, p_md)

r = db.execute('SELECT P_MD(md5sum),P_DATA(data),data FROM data LIMIT 1')
for i in r:
    print
    # Don't want to print the thousands of bytes in i[-1]
    print i[:1]
    print hashlib.md5(i[-1]).hexdigest()

python test.py
[u'3040158ef2c323aaa63da499fc821d77']
[None]

('3040158ef2c323aaa63da499fc821d77', None)
3040158ef2c323aaa63da499fc821d77

编辑

我将我的主要程序归结为下面的脚本,以便更轻松地分享与我完全相同的内容 运行。测试二进制数据(图片)is my avatar image.

tagged.db

的简单初始化程序
PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
PRAGMA writable_schema=ON;
INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)VALUES('table','files','files',0,'CREATE VIRTUAL TABLE "files" USING fts3(fname TEXT, orig_name TEXT, tags TEXT, md5sum TEXT)');
CREATE TABLE 'files_content'(docid INTEGER PRIMARY KEY, 'c0fname', 'c1orig_name', 'c2tags', 'c3md5sum');
CREATE TABLE 'files_segments'(blockid INTEGER PRIMARY KEY, block BLOB);
CREATE TABLE 'files_segdir'(level INTEGER,idx INTEGER,start_block INTEGER,leaves_end_block INTEGER,end_block INTEGER,root BLOB,PRIMARY KEY(level, idx));
CREATE TABLE data (md5sum TEXT PRIMARY KEY, data BLOB);
CREATE INDEX idx1 on data(md5sum);
PRAGMA writable_schema=OFF;
COMMIT;

test.py

的内容
import sqlite3
import hashlib

def p_data(x):
    print 'inside p_data'
    print '\t', [x]
    return x

def p_md(x):
    print 'inside p_md'
    print '\t', [x]
    return x

db=sqlite3.connect('tagged.db')
db.text_factory = str

db.create_function('P_DATA', 1, p_data)
db.create_function('P_MD', 1, p_md)

fname = '4f880f29b27d5b2c14399512b7155f96.png'
with open(fname, 'rb') as f:
    data = f.read()
md = hashlib.md5(data).hexdigest()
db.execute('INSERT INTO files VALUES (?,?,?,?)', ('testname.png', fname, 'testtag', md))
db.execute('INSERT INTO data VALUES (?,?)', (md, data))
# Don't commit so tagged.db will be empty each time test.py is started

r = db.execute('SELECT P_MD(md5sum),P_DATA(data),data FROM data LIMIT 1')
for i in r:
    print
    print i[:1]
    print hashlib.md5(i[-1]).hexdigest()

print
print 'Testing "SELECT typeof(data) FROM data LIMIT 1"'
r = db.execute('SELECT typeof(data) FROM data LIMIT 1')
print r.fetchone()

print
print 'Testing "SELECT p_data("Have some text")'
r = db.execute("SELECT p_data('Have some text')")
v = r.fetchone()
print v
print [str(v[0])]

print
print 'Testing "SELECT p_data(x\'112233\')"'
r = db.execute("SELECT p_data(x'112233')")
v = r.fetchone()
print v

运行 python test.py

inside p_md
        [u'c337ae2a8ebd84b7e50240d875b2729e']
inside p_data
        [None]

('c337ae2a8ebd84b7e50240d875b2729e',)
c337ae2a8ebd84b7e50240d875b2729e

Testing "SELECT typeof(data) FROM data LIMIT 1"
('text',)

Testing "SELECT p_data("Have some text")
inside p_data
        [u'Have some text']
('Have some text',)
['Have some text']

Testing "SELECT p_data(x'112233')"
inside p_data
        [<read-write buffer ptr 0x7f31080cad18, size 3 at 0x7f31080cacd8>]
(<read-write buffer ptr 0x7f31080cad18, size 3 at 0x7f31080cacd8>,)
['\x11"3']

test.py 中,您会发现 type(data)str,这意味着它是作为文本插入的,当您读回它时可能会对编码感到困惑。

解决办法是插入一个sqlite3.Binary代替:

db.execute('INSERT INTO data VALUES (?,?)', (md, sqlite3.Binary(data)))