python - 为什么在 oracledb/cx_Oracle (Python) 中不调用输出转换器进行字节转换?

标签 python oracle cx-oracle python-3.11 python-oracledb

我正在尝试使用 Python (3.11) 和 oracledb 库 (1.3.0) 从 Oracle 数据库获取 SDO_GEOMETRY 类型列。我想使用 outputtypehandler 将 SDO_GEOMETRY 实例转换为 pickle 编码字节。如果我尝试将 cursor.var 中的 typ 参数设置为 typ=str,则这对于 NUMBER 列效果很好,但对于 则失败>typ=bytestyp=oracledb.DB_TYPE_RAW 适用于所有类型的列类型。无论 typ 参数值如何,SDO_GEOMETRY 列始终会产生错误。输出转换器甚至没有被调用,如下所示。

这是我的示例代码:

import oracledb
import pickle


def output_type_handler(cursor, name, default_type, size, precision, scale):

    def pickle_converter(obj) -> bytes:
        print(f"Converter called for {name}.")
        return pickle.dumps(obj)

    if default_type == oracledb.DB_TYPE_OBJECT:
        return cursor.var(
            typ=oracledb.DB_TYPE_RAW, 
            size=size, 
            arraysize=cursor.arraysize, 
            outconverter=pickle_converter
        )

# Switch to thick mode
oracledb.init_oracle_client()

ora_connection = oracledb.connect(
    dsn=oracledb.makedsn("ora.local", 1521, "TST"),
    user="test",
    password="test"
)

ora_connection.outputtypehandler = output_type_handler

with ora_connection.cursor() as cursor:
    # GEOMETRIE is an SDO_GEOMETRY column
    recs = cursor.execute("SELECT GEOMETRIE FROM MV_CS_STWG1KP").fetchmany(5)
    print(recs)

输出(请注意,Converter Called for ... 行甚至没有打印,因此从未调用转换器):

Traceback (most recent call last):
  File "/home/jannis/.config/JetBrains/PyCharmCE2023.1/scratches/tmp.py", line 28, in <module>
    num_recs = cursor.execute("SELECT GEOMETRIE FROM MV_CS_STWG1KP").fetchmany(5)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/jannis/PycharmProjects/etl_engine/venv/lib/python3.11/site-packages/oracledb/cursor.py", line 492, in fetchmany
    row = fetch_next_row(self)
          ^^^^^^^^^^^^^^^^^^^^
  File "src/oracledb/impl/base/cursor.pyx", line 397, in oracledb.base_impl.BaseCursorImpl.fetch_next_row
  File "src/oracledb/impl/thick/cursor.pyx", line 132, in oracledb.thick_impl.ThickCursorImpl._fetch_rows
  File "src/oracledb/impl/thick/utils.pyx", line 413, in oracledb.thick_impl._raise_from_odpi
  File "src/oracledb/impl/thick/utils.pyx", line 403, in oracledb.thick_impl._raise_from_info
oracledb.exceptions.DatabaseError: ORA-00932: inconsistent datatypes: expected BINARY got ADT

我必须使用厚模式连接到较旧的 Oracle 数据库。 我该如何解决这个问题?

最佳答案

在序列化之前,您需要转换为 Python 对象。即使删除输出处理程序并显式腌制也会给出错误:

cur.execute("select geometry from testgeometry")
r, = cur.fetchone()
p = pickle.dumps(r) # fails with error "KeyError: '__getstate__'"

请尝试以下操作。它使用类型转换器转换为 Python 对象,然后使用行工厂对其进行 pickle。

class mySDO(object):
    def __init__(self, gtype, elemInfo, ordinates):
        self.gtype = gtype
        self.elemInfo = elemInfo
        self.ordinates = ordinates

obj_type = con.gettype("MDSYS.SDO_GEOMETRY")

def SDOOutputTypeHandler(cursor, name, default_type, size, precision, scale):
    def SDOOutConverter(DBobj):
        return mySDO(int(DBobj.SDO_GTYPE), DBobj.SDO_ELEM_INFO.aslist(), DBobj.SDO_ORDINATES.aslist())

    if default_type == oracledb.DB_TYPE_OBJECT:
        return cursor.var(obj_type, arraysize=cursor.arraysize, outconverter=SDOOutConverter)

cur.outputtypehandler = SDOOutputTypeHandler

cur.execute("select geometry from testgeometry")
cur.rowfactory = lambda *args: pickle.dumps(args)
p = cur.fetchone()
print(p)

但是,对于空间对象使用“众所周知的二进制”(WKB) 格式会更好吗?您可以直接从数据库获取此信息,而不需要输出转换器或行工厂:

oracledb.defaults.fetch_lobs = False

cur = con.cursor()
cur.execute("select sdo_util.to_wkbgeometry(geometry) from testgeometry")
b = cur.fetchone()
print(b)

关于python - 为什么在 oracledb/cx_Oracle (Python) 中不调用输出转换器进行字节转换?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76014335/

相关文章:

python - 您将如何在 Python 中绘制此 3D 可视化图?

database - Oracle 12c - 未插入记录的列默认字符串值 - 改为空

python - ORA-01861 : literal does not match format string error on char variable

python - Oracle Instant 客户端的 Alpine 依赖 hell

python - 无法在 Jupyter Notebook 中导入 tensorflow

python - Django注释中的日差

python - 填充预定义的 pandas 数据框

mysql - UNIQUE 约束与 INSERT 之前的检查

c# - 仅当上下文使用关系数据库提供程序时才能使用特定于关系的方法?

python - 如何使用 python、cx_oracle 将查询的结果集作为字典获取?