Python和ibmdb2:UnicodeDecodeE

2024-03-29 15:01:27 发布

您现在位置:Python中文网/ 问答频道 /正文

我收到了这个错误信息

UnicodeDecodeError: 'ascii' codec can't decode byte 0xc8 in position 38: ordinal not in range(128)

当我尝试用Python执行任何sql查询时,如下面这样:

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

我检查了默认编码,它似乎是'utf8':

^{pr2}$

我还知道this线程,人们在讨论一个非常类似的问题。其中一条建议是:

Have you applied the required database PTFs (SI57014 and SI57015 for 7.1 and SI57146 and SI57147 for 7.2)? They are included as a distreq, so they should have been in the order with your PTFs, but won't be automatically applied.

但是,我不知道什么是数据库PTF以及如何应用它。需要帮助。在

另外,我用的是Windows10。在

编辑

这是我得到错误信息的方法:

>>> 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

Tags: infromclientmostdbstringdriverselect
3条回答

在这种情况下,使用一个utf8环境,使用一个ascii环境;我使用decode方法。在

'ascii' codec can't decode byte 0xc8 

好吧,这很正常,这不是ascii而是utf8字符串:你应该用utf8编码解码。在

^{pr2}$

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

问题是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)和DB2服务器之间不兼容。正如您在client code中看到的,查询的逻辑基本上是:

  1. 提取并检查传入的参数(第4873到4918行)。在
  2. 为查询分配本机对象(最多4954个)。在
  3. 执行查询并解码结果(函数的其余部分)。在

根据我们到目前为止的调查,您知道为查询传递的数据格式良好(因此不是步骤1)。查看步骤2中的错误路径,您将看到解释这些失败的简单错误消息。因此,您在第3步中失败了。在

在查询中引发了一个空异常,当您试图获取错误的详细信息时,您会得到另一个Unicode解码异常。这看起来像是ibm_db中的一个bug,或者是一个配置错误,这意味着您的DB2安装不兼容。那么我们怎么才能找出哪个。。。?在

与其他地方一样,基本上是用代码标记页面。所有ibm的db代码基本上都将字符串解释为ASCII(通过使用StringOBJ_FromASCII将其转换为pythonapi中的调用,这些api坚持接收ASCII字符,否则将抛出unicode异常)。在

根据您的诊断,您可以通过安装/配置您的系统(客户机和DB2服务器)来使用美式英语来证明/反驳这个问题。这应该可以帮助您克服代码页的不兼容性,从而在这里找到真正的错误。在

如果查询确实是通过网络发出的,那么您可能只会得到一个显示从服务器返回的响应的网络跟踪。然而,基于你在日志中什么也没看到的事实,我不相信这会有任何结果。在

如果失败,您需要修补ibm_db代码来处理非ASCII内容—可以向维护人员提出错误报告,也可以自己尝试(如果您知道如何构建和调试C扩展)。在

相关问题 更多 >