DBMS_UTILITY.EXEC_DDL_STATEMENT
solo ejecuta de manera confiable DDL. Si intenta ejecutarlo con un bloque PL/SQL, fallará silenciosamente y no ejecutará nada.
Esto se puede demostrar ejecutando un bloque PL/SQL que obviamente debería fallar. El siguiente código debería generar ORA-01476: divisor is equal to zero
. Pero en cambio no hace nada.
begin
[email protected](
q'[declare v_test number; begin v_test := 1/0; end;]'
);
end;
/
Utilice un procedimiento temporal para ejecutar un bloque PL/SQL de forma remota. Cree el procedimiento con DBMS_UTILITY.EXEC_DDL_STATEMENT
y luego llamarlo con 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
Creo que este comportamiento es un error. Oracle debería arrojar un error en lugar de simplemente no hacer nada.
Bienvenido al infierno de la concatenación. Las cuerdas se ensucian cuando están incrustadas a 4 niveles de profundidad. Pero hay algunas cosas que puede hacer para facilitarle la vida:
- Utilice un mecanismo de cotización alternativa anidada. Por ejemplo,
q'[ ... ]'
, dentro de unq'< ... >'
, etc. - Utilice cadenas de varias líneas. No es necesario concatenar varias líneas, solo use una sola cadena.
- Utilice espacios adicionales para ayudar a identificar el inicio y el final de las cadenas. Cuando las cosas se ponen tan locas, vale la pena poner un delimitador de cadena en una línea solo, para que todo sea fácil de alinear.
- Utilice
REPLACE
en lugar de concatenación.
Volví a formatear parte de su código usando esos consejos. Stackoverflow no comprende el mecanismo de cotización alternativo, pero las cadenas deberían verse mejor en un buen editor de 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;
/