Python和IBM DB2:UnicodeDecodeError

5

我遇到了这个错误信息:

UnicodeDecodeError: 'ascii'编解码器无法解码第38个字符0xc8:该数值不在128的范围内

当我尝试在Python中执行任何SQL查询时,就会出现这种情况,例如:

>>> import ibm_db
>>> conn = ibm_db.connect("sample","root","root")
>>> ibm_db.exec_immediate(conn, "select * from act")

我检查了默认编码,它似乎是'utf8':
>>> import sys
>>> sys.getdefaultencoding()
'utf-8'

我还了解到这个帖子,人们在讨论一个类似的问题。其中一个建议是:

您是否应用了所需的数据库 PTF(7.1 的 SI57014 和 SI57015,7.2 的 SI57146 和 SI57147)?它们包含在 distreq 中,因此它们应该已经随您的 PTF 一起被订购,但不会自动应用。

然而,我不知道什么是数据库 PTF,也不知道如何应用它。需要帮助。

PS。我使用的是 Windows 10。

编辑

这就是我收到的错误消息:

>>> print(ibm_db.stmt_errormsg())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc8 in position 38:    
ordinal not in range(128)

但是当我在 DB2 CLP 中运行相同的查询"select * from act"时,则可以正常运行。以下是在Python中运行此代码时获得的驱动程序信息:

if client:
    print("DRIVER_NAME: string(%d) \"%s\"" % (len(client.DRIVER_NAME), client.DRIVER_NAME))
    print("DRIVER_VER: string(%d) \"%s\"" % (len(client.DRIVER_VER), client.DRIVER_VER))
    print("DATA_SOURCE_NAME: string(%d) \"%s\"" % (len(client.DATA_SOURCE_NAME), client.DATA_SOURCE_NAME))
    print("DRIVER_ODBC_VER: string(%d) \"%s\"" % (len(client.DRIVER_ODBC_VER), client.DRIVER_ODBC_VER))
    print("ODBC_VER: string(%d) \"%s\"" % (len(client.ODBC_VER), client.ODBC_VER))
    print("ODBC_SQL_CONFORMANCE: string(%d) \"%s\"" % (len(client.ODBC_SQL_CONFORMANCE), client.ODBC_SQL_CONFORMANCE))
    print("APPL_CODEPAGE: int(%s)" % client.APPL_CODEPAGE)
    print("CONN_CODEPAGE: int(%s)" % client.CONN_CODEPAGE)
    ibm_db.close(conn)
else:
    print("Error.")

它会打印出:

DRIVER_NAME: string(10) "DB2CLI.DLL"
DRIVER_VER: string(10) "10.05.0007"
DATA_SOURCE_NAME: string(6) "SAMPLE"
DRIVER_ODBC_VER: string(5) "03.51"
ODBC_VER: string(10) "03.01.0000"
ODBC_SQL_CONFORMANCE: string(8) "EXTENDED"
APPL_CODEPAGE: int(1251)
CONN_CODEPAGE: int(1208)
True

编辑

我也尝试了这个:

>>> cnx = ibm_db.connect("sample","root","root")
>>> query = "select * from act"
>>> query.encode('ascii')
b'select * from act'
>>> ibm_db.exec_immediate(cnx, query)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
Exception
>>> print(ibm_db.stmt_errormsg())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc8 in position 38: 
ordinal not in range(128)

正如您所看到的,在这种情况下,我也收到了完全相同的错误消息。

摘要

以下是我所有的尝试:

C:\Windows\system32>chcp
Active code page: 65001

C:\Windows\system32>python
Python 3.4.4 (v3.4.4:737efcadf5a6, Dec 20 2015, 20:20:57) [MSC v.1600 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import ibm_db
>>> cnx = ibm_db.connect("sample","root","root")
>>> ibm_db.exec_immediate(cnx, "select * from act")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
Exception
>>> print(ibm_db.stmt_errormsg())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc8 in position 38: ordinal not in range(128)
>>> ibm_db.exec_immediate(cnx, b"select * from act")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
Exception: statement must be a string or unicode
>>> query = "select * from act"
>>> query = query.encode()
>>> ibm_db.exec_immediate(cnx, query)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
Exception: statement must be a string or unicode
>>> ibm_db.exec_immediate(cnx, "select * from act").decode('cp-1251')
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
Exception

当我执行 get db cfg 命令时,会得到一个非常长的信息列表。在这个列表中,例如我可以看到默认数据库编码是 UTF-8。顺便说一下,我可以在控制台中使用数据库 - 我可以连接到数据库实例并执行简单的查询。整个问题出现在 Python 驱动程序上。 - Jacobian
是否返回了错误编号,该错误是DB2还是PHP错误? - data_henrik
假设您已经证明了您的查询是ASCII编码,我能看到的唯一其他选项是您正在获取非ASCII响应。查看ibm_db代码,如果您正在运行Python 2,它似乎不会喜欢那个...您是否正在运行Python 2?如果是这样,您尝试过Python 3吗?如果不可能,请尝试使用Wireshark或DB2日志查看请求是否到达服务器以及其响应是什么? - Peter Brittain
@Peter Brittain。我正在使用Python 3。我将在两天内尝试使用Wireshark和DB2日志。谢谢! - Jacobian
真遗憾。嗯,你肯定在客户端C代码中遇到了错误。此时,我认为你必须深入调试此代码,并查看本地库返回的错误... - Peter Brittain
显示剩余24条评论
3个回答

2
您遇到的问题是客户端代码(ibm_db)与DB2服务器之间的不兼容性。如您在客户端代码中所看到的,您的查询逻辑基本上是:
1.提取和检查传递的参数(第4873到4918行)。
2.为查询分配本机对象(最多4954个)。
3.执行查询并解码结果(函数的其余部分)。
根据我们目前的调查,您知道您为查询传递的数据格式正确(因此不是步骤1)。在步骤2中查看错误路径,您会看到简单的错误消息解释这些失败。因此,您在步骤3中失败了。
您在查询上引发了一个空异常,当您尝试获取错误的详细信息时,您会收到另一个Unicode解码异常。这看起来像是ibm_db中的一个错误或配置错误,这意味着您的DB2安装不兼容。那么我们怎么知道哪个是哪个...?
如其他地方所标记的那样,问题基本上与代码页有关。所有ibm_db代码基本上将字符串解释为ASCII(通过使用StringOBJ_FromASCII将它们转换,该函数映射到调用Python API,这些API坚持接收ASCII字符 - 如果不是,则会抛出Unicode异常)。
根据您的诊断,您可以尝试通过安装/配置系统(客户端和DB2服务器)以使用美式英语来证明/否定此问题。这应该可以让您克服代码页不兼容性,以找到真正的错误。
如果查询确实通过网络发送,您可能只会得到一个网络跟踪,显示从服务器返回的响应。但是,基于您在日志中看到的内容为空的事实,我不确定这将产生任何成果。
如果以上方法都无法解决问题,您需要修补ibm_db代码以处理非ASCII内容-通过向维护者提出错误报告或自己尝试(如果您知道如何构建和调试C扩展)。

谢谢你的帮助。但现在看来,ibm_db库似乎根本不兼容Python 3。你有没有尝试过从Python 3代码连接到DB2? - Jacobian
我个人没有使用过它,但是 ibm_db 库与 Python 3 兼容。这在 https://pypi.python.org/pypi/ibm_db/ 中有清晰的文档说明,并且该库是为 Python 2 和 3 编写的。你的问题不是 Python 3。但我怀疑维护者只在美式英语系统上使用过它。 - Peter Brittain
最后一点想法……您最好在GitHub项目中提出问题 - Peter Brittain
谢谢,彼得!我可能会这样做。 - Jacobian

1
问题在于DB2服务器返回的是CP-1251(也称为Windows-1251)文本(如APPL_CODEPAGE: int(1251)所示),这会导致Python(特别是交互式Python REPL)期望UTF-8或ASCII输出,因此会出现问题。
解决方案是执行以下操作:
ibm_db.exec_immediate(conn, "select * from act").decode('cp-1251')

此外,您需要确保终端的文本编码设置为UTF-8。更改该设置的详细信息将取决于您使用的特定终端。由于您已经说过您正在使用cmd,因此适当的命令是chcp 65001

我希望它能够工作,但是它并没有工作。当我运行 ibm_db.exec_immediate(cnx, b"select * from act") 时,我会得到这个错误信息:Exception: statement must be a string or unicode - Jacobian
尝试使用 ibm_db.exec_immediate(cnx, "select * from act").decode('cp-1251') - user2508324
在这种情况下,我再次收到了我的第一个错误信息'ascii' codec can't decode byte 0xc8 in position 38: ordinal not in range(128) - Jacobian
我正在使用Windows的cmd工具。至于文本编码,我不确定如何检查它。 - Jacobian
cmd中输入chcp会返回866。正如你所说,它不是utf8编码。我现在会尝试进行更改。 - Jacobian
显示剩余5条评论

0
在这种情况下,使用utf8环境,但需要ascii环境的内容时,我会使用解码方法。
'ascii' codec can't decode byte 0xc8 

好的,这很正常,这不是ASCII而是UTF8字符串:您应该使用UTF8编码进行解码。

...  
query.decode('utf8')  
ibm_db.exec_immediate(cnx, query)

之后您可能需要重新编码结果以便写入或打印。


我马上检查一下。 - Jacobian
不起作用。query.decode('utf8') 导致 AttributeError: 'str' object has no attribute 'decode' - Jacobian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接