我在db链接上执行ddl语句时遇到问题。 PL / SQL下面负责通过db链接在远程数据库上执行语句,但是我需要将ddl_statement变量作为clob,因为最大varchar2对它来说是不够的。目前它正在提高:
PLS-00564:在远程服务器
的调用中不允许使用Lob参数DECLARE
vi_handler INTEGER;
vi_numberOfRows INTEGER;
BEGIN
vi_handler := DBMS_SQL.open_cursor%s;
DBMS_SQL.parse%s (vi_handler, :ddl_statement, DBMS_SQL.native);
vi_numberOfRows := DBMS_SQL.execute%s (vi_handler);
DBMS_SQL.close_cursor%s (vi_handler);
END;
提前感谢您的任何帮助
答案 0 :(得分:1)
嗯,这很痛苦,如果你可以在远程端有一个你可以打电话的程序会更简单(我知道你不能!);但是通过一些努力,您可以远程运行匿名块,并让匿名块运行您的DDL。
这很令人困惑,因为您需要通过在此端运行的匿名块对远程数据库执行dbms_sql
次调用; 和您需要在本地数据库上执行dbms_sql
调用才能远程运行匿名块。
目前我已在远程端使用r_
为变量等添加前缀,并在本地末端使用l_
作为前缀。我不确定是否足以让事情变得清晰,但这只是一个开始。
让我们使用您尝试的版本,使用带有简单包调用的本地CLOB而不是真正的DDL:
declare
l_stmt clob;
l_c pls_integer;
l_rc pls_integer;
begin
l_stmt := 'begin dbms_stats.gather_schema_stats(user); end;';
l_c := dbms_sql.open_cursor@dblink;
dbms_sql.parse@dblink(l_c, l_stmt, dbms_sql.native);
l_rc := dbms_sql.execute@dblink(l_c);
dbms_sql.close_cursor@dblink(l_c);
end;
/
正如预期的那样:
ORA-06550: line 9, column 31:
PLS-00564: lob arguments are not permitted in calls to remote server
正如评论中所建议的,也许我可以将CLOB拆分成块并重新组装。如果我实际上是在远程服务器上,我可以做这样的事情,现在手动切断我的陈述:
var b1 varchar2(20);
var b2 varchar2(20);
var b3 varchar2(20);
exec :b1 := 'begin dbms_stats.gat';
exec :b2 := 'her_schema_stats(use';
exec :b3 := 'r); end;';
declare
r_stmt clob := :b1 || :b2 || :b3;
r_c pls_integer;
r_rc pls_integer;
begin
r_c := dbms_sql.open_cursor;
dbms_sql.parse(r_c, r_stmt, dbms_sql.native);
r_rc := dbms_sql.execute(r_c);
dbms_sql.close_cursor(r_c);
end;
/
PL/SQL procedure successfully completed.
所以现在我想远程运行同样的东西。该匿名块成为本地解析的语句:
declare
l_stmt clob;
l_remote_stmt varchar2(32767);
l_c integer;
l_rc integer;
begin
l_stmt := 'begin dbms_stats.gather_schema_stats(user); end;';
l_remote_stmt := q'[
declare
r_stmt clob := :b1 || :b2 || :b3;
r_c pls_integer;
r_rc pls_integer;
pragma autonomous_transaction;
begin
r_c := dbms_sql.open_cursor;
dbms_sql.parse(r_c, r_stmt, dbms_sql.native);
r_rc := dbms_sql.execute(r_c);
dbms_sql.close_cursor(r_c);
end;
]';
l_c := dbms_sql.open_cursor@dblink;
dbms_sql.parse@dblink(l_c, l_remote_stmt, dbms_sql.native);
-- bind the chunks of CLOB
dbms_sql.bind_variable@dblink(l_c, 'B1', dbms_lob.substr(l_stmt, 20, 1));
dbms_sql.bind_variable@dblink(l_c, 'B2', dbms_lob.substr(l_stmt, 20, 21));
dbms_sql.bind_variable@dblink(l_c, 'B3', dbms_lob.substr(l_stmt, 20, 41));
-- execute the anonymous block (which makes its own dbms_sql calls) remotely
l_rc := dbms_sql.execute@dblink(l_c);
dbms_sql.close_cursor@dblink(l_c);
end;
/
PL/SQL procedure successfully completed.
我使用了20个字符块来模仿我之前手动完成的操作。对于真正的DDL,您可以这样做:
dbms_sql.bind_variable@dblink(l_c, 'B1', dbms_lob.substr(l_stmt, 32767, 1));
dbms_sql.bind_variable@dblink(l_c, 'B2', dbms_lob.substr(l_stmt, 32767, 32768));
dbms_sql.bind_variable@dblink(l_c, 'B3', dbms_lob.substr(l_stmt, 32767, 65535));
...可能计算偏移而不是手动输入。对于大型CLOB,将更多连接的绑定变量添加到远程语句,并匹配bind_variable
次调用。
此版本确定CLOB需要拆分的块数,并创建适当的远程语句,并以相同的方式进行绑定:
set serveroutput on
declare
l_stmt clob;
l_remote_stmt varchar2(32767);
l_remote_args varchar2(4000);
l_c integer;
l_rc integer;
begin
-- create valid dummy statement > 32k via comments
l_stmt := 'begin dbms_stats.gather_schema_stats(user); /* ';
-- random garbage as comments
for i in 1..20 loop
l_stmt := l_stmt || dbms_random.string('a', 4000);
end loop;
l_stmt := l_stmt || ' */ end;';
-- for debug only
dbms_output.put_line('l_stmt size: ' || length(l_stmt)
|| ' chunks ' || ceil(length(l_stmt)/32767));
-- build remote bind list dynamically
l_remote_args := ' to_clob(:b1)';
for i in 2..ceil(length(l_stmt)/32767) loop
l_remote_args := l_remote_args || ' || to_clob(:b' || i || ')';
end loop;
-- for debug only
dbms_output.put_line('l_remote_args: ' || l_remote_args);
-- build remote statement, including constructed list of binds
l_remote_stmt := q'[
declare
r_stmt clob := ]' || l_remote_args || q'[;
r_c pls_integer;
r_rc pls_integer;
pragma autonomous_transaction;
begin
r_c := dbms_sql.open_cursor;
dbms_sql.parse(r_c, r_stmt, dbms_sql.native);
r_rc := dbms_sql.execute(r_c);
dbms_sql.close_cursor(r_c);
end;
]';
l_c := dbms_sql.open_cursor@dblink3;
-- parse full remote statement including generated binds
dbms_sql.parse@dblink3(l_c, l_remote_stmt, dbms_sql.native);
-- bind variables using chunks of original CLOB
for i in 1..ceil(length(l_stmt)/32767) loop
dbms_sql.bind_variable@dblink3(l_c, 'B' || i,
dbms_lob.substr(l_stmt, 32767, ((i-1) * 32767) + 1));
l_remote_args := l_remote_args || ' || :b' || i;
end loop;
l_rc := dbms_sql.execute@dblink3(l_c);
dbms_sql.close_cursor@dblink3(l_c);
end;
/
l_stmt size: 80055 chunks 3
l_remote_args: to_clob(:b1) || to_clob(:b2) || to_clob(:b3)
PL/SQL procedure successfully completed.
答案 1 :(得分:1)
看看这个,它可能会有所帮助 https://github.com/HowdPrescott/Lob_Over_DBLink
感谢@Phonolog,明白了。 而且你是对的,它实际上并没有回答这个问题,而是指向可能有所帮助的方向。
那怎么样。
你能否将dbms_sql解析重载与dbms_sql.varchar2a类型(varchar2表(32767))一起使用?
按照这个例子:
DECLARE
vi_handler INTEGER;
vi_numberOfRows INTEGER;
ddl_statement DBMS_SQL.varchar2a@some_dblink;
BEGIN
ddl_statement(1) := 'create or replace function get_dual return varchar2 as ';
ddl_statement(2) := 'v_dual varchar2(1);';
ddl_statement(3) := 'begin ';
ddl_statement(4) := ' select * into v_dual from dual;';
ddl_statement(5) := ' return v_dual;';
ddl_statement(6) := 'end get_dual;';
vi_handler := DBMS_SQL.open_cursor@some_dblink;
DBMS_SQL.parse@some_dblink (vi_handler, ddl_statement, 1, ddl_statement.count, true, DBMS_SQL.native);
vi_numberOfRows := DBMS_SQL.execute@some_dblink (vi_handler);
DBMS_SQL.close_cursor@some_dblink (vi_handler);
END;
答案 2 :(得分:0)
我通过将DDL写入文件,然后使用sqlplus包含该文件来完成此操作。以下是我向所有Oracle实例分发管理包的示例:
c:\ temp \ distribute.sql保存我的DDL
sqlplus /nolog connect /@db1 as sysdba @c:\temp\distribute.sql connect /@db2 as sysdba @c:\temp\distribute.sql ... connect /@dbN as sysdba @c:\temp\distribute.sql
答案 3 :(得分:0)
谢谢你的帮助。我发送了一个负责执行ddls的包 通过dblink远程服务器(该软件包适合varchar2),然后我从1.db上通过dblink从all_source获取软件包sourec。它正在工作,因为在视图中记录了一行包。