ORA-03001: 将 XMLTYPE 从表转换为 NCLOB 时未实现的功能

Posted

技术标签:

【中文标题】ORA-03001: 将 XMLTYPE 从表转换为 NCLOB 时未实现的功能【英文标题】:ORA-03001: unimplemented feature when converting XMLTYPE to NCLOB from table 【发布时间】:2018-06-22 13:30:00 【问题描述】:

当我尝试从从表中获取的 XMLTYPE 转换为 nclob 时,出现错误:

ORA-03001:未实现的功能

当我对动态创建的 XMLTYPE 尝试相同的操作时,一切正常。

我的 Oracle 版本是:12.1.0.2.0

代码示例:

这工作正常:

DECLARE
    v_xml XMLTYPE;
    v_clob  CLOB;
    v_nclob nCLOB;
BEGIN
    SELECT XMLTYPE('<a>test</a>') INTO v_xml FROM dual;
    v_clob := v_xml.getClobVal();
    v_nclob := to_nclob(v_clob);
END
;

这会产生错误:

CREATE TABLE TEST_XMLTYPE_TO_NCLOB
(
      XML_MSG SYS.XMLTYPE
)
;
INSERT INTO TEST_XMLTYPE_TO_NCLOB (XML_MSG) VALUES (XMLTYPE('<a>test</a>'))
;
SET SERVEROUTPUT ON;
DECLARE
    v_xml       XMLTYPE;
    v_clob  CLOB;
    v_nclob nCLOB;
BEGIN
    SELECT XML_MSG INTO v_xml FROM TEST_XMLTYPE_TO_NCLOB WHERE rownum = 1;
    v_clob := v_xml.getClobVal();
    v_nclob := to_nclob(v_clob);
END
;

我想知道这是我的错误还是 oracle 错误?

以及如何以可行的方式对从表中获取的数据进行从 XMLTYPE 到 NCLOB 的转换。

顺便说一句 - 为什么我不能用 WHEN OTHERS 捕获这个异常?

【问题讨论】:

【参考方案1】:

我认为这与表存储using SecureFile storage 有关,它不支持或与 NCLOB 交互。您为查询创建的 XMLType 不使用 SecureFile(或任何)存储,因此不受影响。

编译器似乎发现您将使用 SecureFile 存储的值 - 可能会导致不同风格的 XMLType(我没有看到这个文档,但似乎您可能不使用不同的内部类型'通常不需要担心,就像日期一样;虽然dump() 说它们都是 58 型)。

为什么它抱怨你使用从中提取的 CLOB 值有点神秘。也许编译器正在以某种方式重写代码,这意味着它认为 XMLType 被更直接地使用。或者更可能的是,CLOB 的风格也略有不同。 (根据@BobJarvis 的观察,我认为这很可能。)

当您尝试操作 PL/SQL 变量时,编译器会抛出错误 - 这是编译时错误,而不是运行时异常,这就是您无法捕获它的原因。

您可以通过将 CLOB 转换回 XMLType(现在可能是不同的变体??)然后再次转换回 CLOB(不同的变体?)来解决它:

DECLARE
    v_xml XMLTYPE;
    v_clob  CLOB;
    v_nclob nCLOB;
BEGIN
    SELECT XML_MSG INTO v_xml FROM TEST_XMLTYPE_TO_NCLOB WHERE rownum = 1;
    v_clob := v_xml.getClobVal();
    v_xml := xmltype(v_xml.getClobVal());
    v_clob := v_xml.getClobVal();
    v_nclob := to_nclob(replace(v_clob, chr(10), null));
END
;
/

PL/SQL procedure successfully completed.

为什么会这样,为什么它是必要的,也是一个谜;但建议以某种方式涉及不同风格的数据类型,或者至少我是这样解释的。

对于您的实际情况,它也可能不实用。您也可以将其作为查询的一部分进行:

DECLARE
    v_xml XMLTYPE;
    v_clob  CLOB;
    v_nclob nCLOB;
BEGIN
    SELECT XMLTYPE(t.XML_MSG.getClobVal()) INTO v_xml
    FROM TEST_XMLTYPE_TO_NCLOB t WHERE rownum = 1;
    v_clob := v_xml.getClobVal();
    v_nclob := to_nclob(replace(v_clob, chr(10), null));
END
;
/

PL/SQL procedure successfully completed.

这并没有好多少,但您也许可以将其隐藏得更多。或者您也可以通过显式将 XMLType 存储为 CLOB 或二进制来避免它,但这也可能不是一个选项或理想的。

这可能需要向 Oracle 支持提出服务请求。这可能是一个已知的错误,但可能会被视为预期行为(另请参阅稍微相关的文档 ID 1546992.1)。

【讨论】:

您的解决方案似乎有效,您的解释很有道理,所以我相信它。 ;) 再次感谢您,Alex Poole。【参考方案2】:

至于发生了什么

看来,当写入 XMLTYPE 列的数据被读回并转换为 CLOB 时,会在末尾添加两个行尾序列 (LF/LF)。通过在v_clob := v_xml.getClobVal(); 之后添加以下内容,尝试在转换后打印出 CLOB:

DBMS_OUTPUT.PUT_LINE('DBMS_OUTPUT.PUT_LINE('v_clob=' || v_clob);

当对从你得到的数据库中获取的 XMLTYPE 转换的 CLOB 数据运行上述操作时

<a>test</a>

后面有两个换行符。当您在从内联 XMLTYPE 转换的 CLOB 上运行 DBMS_OUTPUT.PUT_LINE 时,您会得到 ​​p>

<a>test</a>

后面没有换行符。

现在,事情是这样的 - 如果您尝试将从 XMLTYPE 在数据库中 转换的 CLOB 传递给 TRIM 函数,您将得到 ORA-03001: unimplemented feature。如果您将从内联 XMLTYPE 转换的 CLOB 传递给 TRIM 函数,它可以正常工作。所以这个问题与TO_NCLOB 无关 - 似乎每当您尝试使用从数据库中的 XMLTYPE 值转换而来的 CLOB 时都会发生这种情况。我不知道如何解决或解决此问题。

至于在 WHEN OTHERS 中捕获 -30001 异常 - 它在 11.2g 中对我来说很好。

祝你好运。

【讨论】:

我认为换行只是存储的产物;如果你从 PL/SQL CLOB 变量中删除这些,它似乎没有任何区别。如果在查询中由trim()to_nclob() 抛出错误,您也可以捕获-30001,但如果它是由PL/SQL 抛出的,则不能捕获,这本身很有趣。 @AlexPoole - 我的测试代码在 PL/SQL 块中调用 TRIM 时捕获了异常(在 WHEN OTHERS 中)。 ???另外 - 你是如何从 CLOB 中删除换行符的? 更有趣;在 PL/SQL 中,您可以在运行时从 trim() 捕获错误,但不能从 to_nclob() 捕获 - 编译器似乎抛出了那个错误。乐趣。我刚刚使用了replace(v_clob, chr(10), null)

以上是关于ORA-03001: 将 XMLTYPE 从表转换为 NCLOB 时未实现的功能的主要内容,如果未能解决你的问题,请参考以下文章

pl/sql:将 xmltype 转换为节点

将数据从表传输到 XML 对象表

存储过程中未实现的功能错误

将 oracle xmltype 表字段选择到 xmltype 变量中会导致空对象

拆分 XMLTYPE 以根据条件创建两个 XMLTYPE

将 SQL Server 存储过程转换为 Oracle 过程以从表中查询