DBMS_UTILITY.EXEC_DDL_STATEMENT
draait alleen betrouwbaar DDL. Als je het probeert uit te voeren met een PL/SQL-blok, zal het stil mislukken en wordt er niets uitgevoerd.
Dit kan worden aangetoond door een PL/SQL-blok uit te voeren dat uiteraard zou moeten mislukken. De onderstaande code moet genereer ORA-01476: divisor is equal to zero
. Maar in plaats daarvan doet het niets.
begin
[email protected](
q'[declare v_test number; begin v_test := 1/0; end;]'
);
end;
/
Gebruik een tijdelijke procedure om een PL/SQL-blok op afstand uit te voeren. Maak de procedure met DBMS_UTILITY.EXEC_DDL_STATEMENT
en roep het dan aan met native dynamische 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
Ik denk dat dit gedrag een bug is. Oracle zou een foutmelding moeten geven in plaats van simpelweg niets te doen.
Welkom in de aaneenschakeling van de hel. Strings worden rommelig als ze 4 niveaus diep zijn ingebed. Maar er zijn een paar dingen die u kunt doen om het leven gemakkelijker te maken:
- Gebruik geneste alternatieve aanhalingstekens. Bijvoorbeeld
q'[ ... ]'
, in eenq'< ... >'
, enz. - Gebruik tekenreeksen met meerdere regels. Het is niet nodig om meerdere regels samen te voegen, gebruik gewoon een enkele string.
- Gebruik extra spaties om het begin en einde van tekenreeksen te identificeren. Als de dingen zo gek worden, is het de moeite waard om alleen een tekenreeksscheidingsteken op een regel te plaatsen, zodat alles gemakkelijk op een rij kan worden gezet.
- Gebruik
REPLACE
in plaats van aaneenschakeling.
Ik heb een deel van je code opnieuw geformatteerd met behulp van die tips. Stackoverflow begrijpt het alternatieve aanhalingsmechanisme niet, maar de strings zouden er beter uit moeten zien in een goede Oracle SQL-editor.
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;
/