【发布时间】:2012-11-23 18:35:51
【问题描述】:
我使用 Oracle 11g(在 Red Hat 上)。我有一个带有 XMLType 列的简单常规表:
CREATE TABLE PROJECTS
(
PROJECT_ID NUMBER(*, 0) NOT NULL,
PROJECT SYS.XMLTYPE,
);
我使用 Oracle SQL Developer(在 Windows 上):
select T1.PROJECT P1 from PROJECTS T1 where PROJECT_ID = '161';
它有效。我得到一个细胞。我可以双击并下载整个 XML 文件。
然后我尝试将结果作为 CLOB:
select T1.PROJECT.getClobVal() P1 from PROJECTS T1 where PROJECT_ID = '161';
它有效。我得到一个细胞。我可以双击并查看整个文本并复制它。但有一个问题。当我将它复制到剪贴板时,我只得到前 4000 个字符。位置 4000 似乎有 0x00 字符,而 CLOB 的其余部分没有被复制。
为了确认这一点,我在 java 中写了检查:
// ... create projectsStatement
Reader reader = projectsStatement.getResultSet().getCharacterStream( "P1" );
BufferedReader bf = new BufferedReader( reader );
char buffer[] = new char[ 1024 ];
int count = 0;
int globalPos = 0;
while ( ( count = bf.read( buffer, 0, buffer.length ) ) > 0 )
for ( int i = 0; i < count; i++, globalPos++ )
if ( buffer[ i ] == 0 )
throw new Exception( "ZERO at " + Integer.toString(globalPos) );
阅读器返回完整的 XML,但我的异常被抛出,因为位置 4000 处有空字符。我可以删除这个单字节,但这将是一个相当奇怪的解决方法。
我在那里没有使用 VARCHAR2,但也许这个问题与 VARCHAR2 限制(4000 字节)有关?还有其他想法吗?这是 Oracle 错误还是我遗漏了什么?
-------------------- 编辑 --------------------
使用以下存储过程插入值:
create or replace
procedure addProject( projectId number, projectXml clob ) is
sqlstr varchar2(2000);
begin
sqlstr := 'insert into projects ( PROJECT_ID, PROJECT ) VALUES ( :projectId, :projectData )';
execute immediate sqlstr using projectId, XMLTYPE(projectXml);
end;
用于调用它的 Java 代码:
try ( CallableStatement cs = connection.prepareCall("{call addProject(?,?)}") )
{
cs.setInt( "projectId", projectId );
cs.setCharacterStream( "projectXml", new StringReader(xmlStr) , xmlStr.length() );
cs.execute();
}
-------- 编辑。简单测试--------
我将使用从您的答案中学到的所有知识。创建最简单的表:
create table T1 ( P XMLTYPE );
准备两个带有 XML 的 CLOB。第一个带有空字符,第二个没有。
declare
P1 clob;
P2 clob;
P3 clob;
begin
P1 := '<a>';
P2 := '<a>';
FOR i IN 1..1000 LOOP
P1 := P1 || '0123456789' || chr(0);
P2 := P2 || '0123456789';
END LOOP;
P1 := P1 || '</a>';
P2 := P2 || '</a>';
检查 null 是否在第一个 CLOB 中,而不是在第二个中:
DBMS_OUTPUT.put_line( DBMS_LOB.INSTR( P1, chr(0) ) );
DBMS_OUTPUT.put_line( DBMS_LOB.INSTR( P2, chr(0) ) );
我们会得到预期的结果:
14
0
尝试将第一个 CLOB 插入 XMLTYPE。不起作用。无法插入这样的值:
insert into T1 ( P ) values ( XMLTYPE( P1 ) );
尝试将第二个 CLOB 插入 XMLTYPE。它会起作用的:
insert into T1 ( P ) values ( XMLTYPE( P2 ) );
尝试将插入的 XML 读入第三个 CLOB。它会起作用的:
select T.P.getClobVal() into P3 from T1 T where rownum = 1;
检查是否有空。没有空值:
DBMS_OUTPUT.put_line( DBMS_LOB.INSTR( P3, chr(0) ) );
似乎数据库内部没有空值,只要我们在 PL/SQL 上下文中,就没有空值。但是当我尝试在 SQL Developer(在 Windows 上)或 Java(在 Red Hat EE 和 Tomcat7 上)中使用以下 SQL 时,我在所有返回的 CLOB 中的位置 4000 处得到空字符:
select T.P.getClobVal() from T1 T;
BR, 杰米
【问题讨论】:
-
您可以使用
utl_file将其写入文件并查看内容的样子吗?你也可以试试select XMLType.getClobVal(PROJECT) from PROJECTS;吗? (虽然功能上没有什么不同) -
列是如何填充的?您确定问题出在检索上吗?如果不同的客户看到相同的东西,这听起来不太可能。您还可以选择该值的子串并查看空字符是否仍在其中。
-
我跑了utlfile.sql和prvtfile.plb,还是不能使用utl_file(ORA-06521: PL/SQL: Error mapping function),对不起。
-
我使用了 XMLType.getClobVal(PROJECT) 并且有空字符。然后我使用了 T1.PROJECT.getBlobVal(nls_charset_id('AL32UTF8')) 并且下载的 blob 中没有空字符(使用 SQL Developer 或 Java)。
-
@Alex 我编辑了我的帖子。似乎确实 null 不存在,因为不可能以这种方式填充 XMLTYPE 列。看来问题出在检索上。