我有接收XML的程序:
CREATE OR REPLACE PROCEDURE PROCESS_XML(xml IN CLOB) AS
BEGIN
DBMS_OUTPUT.PUT_LINE('XML processing started');
END;
现在我正在做一个bash脚本,它将从服务器下载一些XML文件,对于每一个,我将使用SQL Plus调用上述过程。
#!/bin/bash
file=$(curl -s "http://example.com/someFile.xml");
sqlplus myuser/mypass@myhost:1521/myscheme <<< "EXECUTE PROCESS_XML('$file')";
它适用于小文件,但对于大文件,我收到以下错误:
SQL*Plus: Release 12.1.0.2.0 Production on Thu Jun 8 18:28:19 2017
Copyright (c) 1982, 2016, Oracle. All rights reserved.
Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
With the Partitioning, Real Application Clusters, Automatic Storage Management, OLAP
and Data Mining options
SQL> Input truncated to 7499 characters
SP2-0027: Input is too long (> 2499 characters) - line ignored
为了发送那些大的XML,我有什么可以做的吗?
由于
答案 0 :(得分:3)
您可以将文件内容拆分为SQL * Plus将接受的块,然后在匿名PL / SQL块中重新组合它们;这也将允许比字符串文字更长的值。例如:
#!/bin/bash
file=$(curl -s "http://example.com/someFile.xml" | sed -r "s/(.{1,2000})/l_clob := l_clob || '\1';\n/g")
sqlplus -s -l myuser/mypass@myhost:1521/myscheme <<!EOF
set serveroutput on
declare
l_clob clob := '';
begin
${file}
PROCESS_XML(l_clob);
end;
/
exit
!EOF
无论如何, EXECUTE
是一个简单的匿名块的包装器,所以使用heredoc而不是herestring只是让你扩展它来做更多。该块声明一个空CLOB,然后从文件中附加块 - 每个块都转换为:
l_clob := l_clob || '<up to 2000 chars>';
当SQL * Plus看到它时,构造的heredoc最终为:
set serveroutput on
declare
l_clob clob := '';
begin
l_clob := l_clob || '<first 2000 chars>';
l_clob := l_clob || '<next 2000 chars>';
l_clob := l_clob || '<next 2000 chars>';
...
l_clob := l_clob || '<last 2000 chars>';
PROCESS_XML(l_clob);
end;
/
exit
稍微修改您的程序,部分是为了验证传入的长度,部分是为了检查XML在此过程中是否已损坏:
CREATE OR REPLACE PROCEDURE PROCESS_XML(xml IN CLOB) AS
BEGIN
DBMS_OUTPUT.PUT_LINE('XML processing started; CLOB length: '
|| length(xml));
DBMS_OUTPUT.PUT_LINE('XML processing started; converted XML length: '
|| length(xmltype(xml).getclobval()));
END;
/
使用该脚本处理大文件会产生输出:
XML processing started; CLOB length: 368104
XML processing started; converted XML length: 368104
PL/SQL procedure successfully completed.
当然,这会让事情变慢一些; ~360k文件在我的系统上花了大约13秒。可能存在比sed
更快的机制,但原则仍然适用。
macOS上的sed
版本(需要-E
而不是GNU的-r
标志)似乎仅限于255次重复模式(通过{{1在RE_DUMP_MAX
中设置,而不是我知道在运行时可以修改的。)
您可以使用下限:
limits.h
在Linux下实际上要快得多,所以无论如何都不是一个糟糕的选择。
在对macOS进行进一步实验之后(El Cap,但对Sierra来说可能是相同的)并尝试使用转义换行符而不在输出中包含文字file=$(curl -s "http://example.com/someFile.xml" | sed -E "s/(.{1,255})/l_clob := l_clob || '\1';\n/g")
或n
,从而导致PLS-00103 ,将实际的换行放在:
\n
答案 1 :(得分:0)
您可以尝试循环输入文件,一次附加2.4k块,可能是:
variable l_var clob;
exec :l_var := '';
-- loop here
exec :l_var := :l_var || '$chunk';
---
exec process_xml(:l_var);
而不是shell脚本,你也可以用Java形成clob,例如,逐行读取XML,它没有变量大小的限制。
答案 2 :(得分:0)
你能尝试用bash压缩文件数据,然后使用utl_compress在PLSQL中解压缩吗?
类似的东西:
#!/bin/bash
file=$(curl -s "http://example.com/someFile.xml" | gzip -f);
sqlplus myuser/mypass@myhost:1521/myscheme <<< "EXECUTE PROCESS_XML('$file')";
在plsql中:
CREATE OR REPLACE PROCEDURE PROCESS_XML(xml IN CLOB) AS
uncomp CLOB;
BEGIN
UTL_COMPRESS.lz_uncompress(src => xml, dst => uncomp);
DBMS_OUTPUT.PUT_LINE('XML processing started');
END;