首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为CLOB设置大值的cx_Oracle失败,因为cx_Oracle.DatabaseError: ORA-03146: TTC字段的无效缓冲区长度。

为CLOB设置大值的cx_Oracle失败,因为cx_Oracle.DatabaseError: ORA-03146: TTC字段的无效缓冲区长度。
EN

Stack Overflow用户
提问于 2017-11-14 01:29:43
回答 1查看 1.7K关注 0票数 0

我试图将一个非常大的值(>536‘m)设置为一个cx_oracle CLOB变量,但它似乎在512’m标记附近失败。

代码语言:javascript
运行
复制
conn = cx_Oracle.connect('foo/bar@baz')
cur = conn.cursor()
clob = cur.var(cx_Oracle.CLOB)

# The following is successful
clob.setvalue(0, 'A' * 1024 * 1024 * 511)

# The following fails
clob.setvalue(0, 'A' * 1024 * 1024 * 512)

第二个命令(或任何大于此的值)在以下情况下失败:

代码语言:javascript
运行
复制
cx_Oracle.DatabaseError: ORA-03146: Invalid buffer length for TTC field

在对第二个命令进行了三次调用之后,会话本身似乎被断开了(而第一个命令没有发生这种情况)。

代码语言:javascript
运行
复制
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
cx_Oracle.OperationalError: ORA-03135: connection lost contact
Process ID: 17567
Session ID: 137 Serial number: 9226

我在两个环境中进行了测试,结果相同: Python在本地环境中连接到本地Oracle;python在远程unix环境中连接到不同的远程Oracle环境。它们都在完全相同的1024 * 1024 * 512线上失败,这使我相信问题可能与cx_Oracle有关。

数据库版本: Oracle 12CR1

Oracle客户端版本: 12.1.0.2.0

cx_Oracle版本: 5.1.3和6.0.3测试结果相同

Python版本: 2.7.13

一切都是64位。

我的用例是,我需要调用一个PLSQL过程将CLOB插入到数据库中。我们的项目是遵循一个特定的ERP规则集,我们不允许做一个直接的DML。我的代码类似于以下代码:

代码语言:javascript
运行
复制
data = get_user_provided_data()

conn = cx_Oracle.connect('foo/bar@baz')
cur = conn.cursor()
clob = cur.var(cx_Oracle.CLOB)
clob.setvalue(0, data)

cur.callproc('xxfoo_bar_pkg.insert_one', 
               keywordParameters={
                   'p_data_i': clob, 
               })
EN

Stack Overflow用户

发布于 2017-11-15 22:05:34

感谢安东尼·图宁加在github回购的回应。

这显然是一个错误,但下面是一个有效的解决方法,它涉及更改PLSQL以使用CLOB的OUT param,以及使用Oracle的empty_clob实例化该值。这将返回一个LOB定位器到python,这有点像一个指向LOB值的指针。您可以写到lob定位器,然后是commit,它会将值写入DB。我不清楚这对网络的影响,但性能似乎类似于

DDLs:

代码语言:javascript
运行
复制
CREATE TABLE xxtest_cx_oracle (
    data CLOB
);


CREATE OR REPLACE PACKAGE xxtest_cx_oracle_pkg
IS
    -- Normal way; limited to ~ 511MB
    PROCEDURE insert_one(
        p_data_i IN CLOB
    );

    -- Workaround; supports > 511MB
    PROCEDURE insert_one_workaround(
        p_data_o OUT CLOB
    );
END;

CREATE OR REPLACE PACKAGE BODY xxtest_cx_oracle_pkg
IS 
    -- Normal way; limited to ~ 511MB
    PROCEDURE insert_one(
        p_data_i IN CLOB
    )
    IS
    BEGIN
        INSERT INTO xxtest_cx_oracle (
            data
        ) VALUES (
            p_data_i
        );
    END;

    -- Workaround; supports > 511MB
    PROCEDURE insert_one_workaround(
        p_data_o OUT CLOB
    )
    IS
    BEGIN
        INSERT INTO xxtest_cx_oracle (
            data
        ) VALUES (
            empty_clob()
        ) RETURNING data INTO p_data_o;
    END;
END;

Python:

代码语言:javascript
运行
复制
import cx_Oracle
conn = cx_Oracle.connect('FOO/bar@BAZ')
cur = conn.cursor()

# Old way, using normal IN param; only supports ~511MB
data = cur.var(cx_Oracle.CLOB)
data.setvalue(0, 'A' * 1024 * 1024 * 511)
cur.callproc('xxtest_cx_oracle_pkg.insert_one', (data,))
conn.commit()

# New way using empty_clob and OUT param; supports > 511MB
data = cur.var(cx_Oracle.CLOB)
cur.callproc('xxtest_cx_oracle_pkg.insert_one_workaround', (data))
lob = data.getvalue()
lob.write('A' * 1024 * 1024 * 512)
conn.commit()

我注意到的一件事是,试图关闭conn将失败:

代码语言:javascript
运行
复制
>>> cursor.close()
>>> conn.close()
Traceback (most recent call last):
   File "<stdin>", line 1, in <module>
cx_Oracle.DatabaseError: DPI-1054: connection cannot be closed when open statements or LOBs exist

但是,您可以只使用del lob,也可以让conn超出范围来解决这个问题。

票数 0
EN
查看全部 1 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47276246

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档