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 时未实现的功能的主要内容,如果未能解决你的问题,请参考以下文章