DBMS_UTILITY.EXEC_DDL_STATEMENT
apenas executa DDL de forma confiável. Se você tentar executá-lo com um bloco PL/SQL, ele falhará silenciosamente e não executará nada. Isso pode ser demonstrado executando um bloco PL/SQL que obviamente deve falhar. O código abaixo deve gerar
ORA-01476: divisor is equal to zero
. Mas, em vez disso, não faz nada. begin
[email protected](
q'[declare v_test number; begin v_test := 1/0; end;]'
);
end;
/
Use um procedimento temporário para executar um bloco PL/SQL remotamente. Crie o procedimento com
DBMS_UTILITY.EXEC_DDL_STATEMENT
e, em seguida, chame-o com SQL dinâmico nativo. 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
Acho que esse comportamento é um bug. O Oracle deve lançar um erro em vez de simplesmente não fazer nada.
Bem-vindo ao inferno da concatenação. As strings ficam confusas quando estão embutidas em 4 níveis de profundidade. Mas existem algumas coisas que você pode fazer para tornar a vida mais fácil:
- Use o mecanismo de cotação alternativa aninhado. Por exemplo,
q'[ ... ]'
, dentro de umq'< ... >'
, etc. - Use strings de várias linhas. Não há necessidade de concatenar várias linhas, basta usar uma única string.
- Use espaçamento extra para ajudar a identificar o início e o fim das strings. Quando as coisas ficam tão loucas, vale a pena colocar um delimitador de string em uma linha sozinho, para que tudo seja fácil de alinhar.
- Usar
REPLACE
em vez de concatenação.
Eu reformulei parte do seu código usando essas dicas. O Stackoverflow não entende o mecanismo de cotação alternativo, mas as strings devem ficar melhores em um bom editor 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;
/