2

我有一个在 sqlite3 中存储一些数据的 python 程序,我想在不同的操作系统中使用它。

在 Windows 7 中,该程序运行良好,但在 Ubuntu 12.04 中却不行。

问题是:当我在我的 sqlite 数据库中存储一个空元组(作为来自 的字符串 " ".join( ... ))然后在 windows 中读回它时,我得到一个空元组(),而在 Ubuntu 中我得到None.

我的测试代码是:

import sqlite3
import os

def adapt_tuple(tpl):
    return " ".join(str(n) for n in tpl)

def get_tuple(s):
    return tuple([int(x) for x in s.split()])

emptytuple=()
goodtuple=(1,2)

sqlite3.register_adapter(tuple,adapt_tuple)
sqlite3.register_converter("tuple_of_ints",get_tuple)

myconn=sqlite3.connect('test.db',detect_types=sqlite3.PARSE_DECLTYPES)
myconn.execute("""CREATE TABLE test(number int, tuple tuple_of_ints);""")

goodentry=(1,goodtuple)
emptyentry=(2,emptytuple)

myconn.execute("""INSERT INTO test VALUES (?,?);""", goodentry)
myconn.execute("""INSERT INTO test VALUES (?,?);""", emptyentry)

for row in myconn.execute("""SELECT * FROM test;"""):
    print row

myconn.close()
os.remove('test.db')

这给了我一个输出:

(1, (1, 2))
(2, ())

在 Windows 和:

(1, (1, 2))
(2, None)

在ubuntu中。

我已经检查过了

get_tuple(adapt_tuple(emptytuple))

在两个系统中给出相同的输出(),所以它必须与通过 sqlite3 有关。

python 中的输出sys.version_info在两个系统中是相同的,sqlite3.version所以我很确定这与操作系统有关。

总而言之,我的问题是:为什么会这样?以及如何让 Ubuntu 版本在最后返回一个空元组?

感谢您的回复。苹果。

笔记

我最初应该提到,如果我打印我的adapt_tuple输出,我会" "在两个操作系统上得到。

4

2 回答 2

1

I can not explain the discrepancy between Windows and Ubuntu, though here is a workaround for Ubuntu:

def adapt_tuple(tpl):
    return " ".join(str(n) for n in tpl) or ' '
于 2013-02-24T19:13:29.690 回答
1

It looks like that one of your sqlite versions is treating empty string in the return of an adapter as a NULL, and maybe you have different sqlite versions that could explain the different behavior.

If that is the case, then you need to modify the adapter in order to not return empty strings. Then it is also needed to adjust the converter to handle the new format. Here is an example for that:

def adapt_tuple(tpl):
    return repr(tpl)

def get_tuple(s):
    if len(s) > 2:
        return tuple(int(x) for x in s[1:-1].split(','))
    return ()

The actual problem is related to register_converter, which relies on sqlite3_column_blob. The later returns NULL for a zero-length BLOB (see the sqlite's documentation). Then in pysqlite's code there is a check in the following form:

if (!sqlite3_column_blob(...)) converted_col = Py_None;

As a consequence, your converter is never called for empty strings and None is returned.

The problem is that pysqlite depends on the behavior of sqlite3_column_blob, which might change between sqlite versions. In fact, that is the case. Starting on sqlite 3.7.3, sqlite3_column_blob was modified to comply with the documentation. Before that, it wouldn't return NULL on empty blobs. So, to be consistent, ensure that your adapter never returns an empty string.

于 2013-02-24T19:13:58.173 回答