DBMS_UTILITY.EXEC_DDL_STATEMENT
надеждно изпълнява само DDL. Ако се опитате да го стартирате с PL/SQL блок, той тихо ще се провали и няма да стартира нищо.
Това може да се демонстрира чрез стартиране на PL/SQL блок, който очевидно трябва да се провали. Кодът по-долу трябва генерира ORA-01476: divisor is equal to zero
. Но вместо това не прави нищо.
begin
[email protected](
q'[declare v_test number; begin v_test := 1/0; end;]'
);
end;
/
Използвайте временна процедура за отдалечено изпълнение на PL/SQL блок. Създайте процедурата с DBMS_UTILITY.EXEC_DDL_STATEMENT
и след това да го извикате със собствен динамичен SQL.
begin
[email protected](
q'[
create or replace procedure test_procedure
is
v_test number;
begin
v_test := 1/0;
end;
]'
);
execute immediate 'begin [email protected]; end;';
end;
/
RESULTS:
ORA-01476: divisor is equal to zero
ORA-06512: at "JHELLER.TEST_PROCEDURE", line 5
ORA-06512: at line 1
ORA-06512: at line 12
Мисля, че това поведение е грешка. Oracle трябва да изведе грешка, вместо просто да не прави нищо.
Добре дошли в ада на конкатенацията. Струните се объркват, когато са вградени на 4 нива дълбоко. Но има няколко неща, които можете да направите, за да улесните живота си:
- Използване на вложен алтернативен механизъм за цитиране. Например
q'[ ... ]'
, вътре вq'< ... >'
и т.н. - Използвайте многоредови низове. Няма нужда да свързвате няколко реда, просто използвайте един низ.
- Използвайте допълнителен интервал, за да идентифицирате началото и края на низовете. Когато нещата станат толкова луди, струва си да поставите разделител на низ на ред сам по себе си, така че всичко да е лесно за подреждане.
- Използвайте
REPLACE
вместо конкатенация.
Преформатирах част от вашия код, използвайки тези съвети. Stackoverflow не разбира алтернативния механизъм за цитиране, но низовете трябва да изглеждат по-добре в добър Oracle SQL редактор.
declare
v_db_name varchar2(30) := 'myself';
sql_update varchar2(32767);
begin
execute immediate replace(
q'[
begin
[email protected]#DB_NAME#
(
q'<
create or replace procedure cw_drop_table is
sql_drop varchar2(2000);
begin
sql_drop :=
q'{
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE iSecurity2_dupes_bak';
EXCEPTION WHEN OTHERS THEN
IF SQLCODE != -942 THEN
NULL;
END IF;
END;
}';
execute immediate sql_drop;
end;
>'
);
execute immediate 'begin [email protected]#DB_NAME#; end;';
end;
]', '#DB_NAME#', v_db_name);
sql_update := 'create table iSecurity2_dupes_bak as select * from iSecurity2';
execute immediate 'begin [email protected]'||v_db_name||
'(:sql_update); end;' using sql_update;
commit;
end;
/