DBMS_UTILITY.EXEC_DDL_STATEMENT
exécute uniquement DDL de manière fiable. Si vous essayez de l'exécuter avec un bloc PL/SQL, il échouera silencieusement et n'exécutera rien.
Cela peut être démontré en exécutant un bloc PL/SQL qui devrait évidemment échouer. Le code ci-dessous devrait génère ORA-01476: divisor is equal to zero
. Mais à la place, il ne fait rien.
begin
[email protected](
q'[declare v_test number; begin v_test := 1/0; end;]'
);
end;
/
Utilisez une procédure temporaire pour exécuter un bloc PL/SQL à distance. Créez la procédure avec DBMS_UTILITY.EXEC_DDL_STATEMENT
puis appelez-le avec SQL dynamique natif.
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
Je pense que ce comportement est un bug. Oracle devrait renvoyer une erreur au lieu de simplement ne rien faire.
Bienvenue dans l'enfer de la concaténation. Les chaînes deviennent désordonnées lorsqu'elles sont intégrées à 4 niveaux de profondeur. Mais il y a quelques choses que vous pouvez faire pour vous faciliter la vie :
- Utilisez un mécanisme de guillemets alternatifs imbriqués. Par exemple,
q'[ ... ]'
, à l'intérieur d'unq'< ... >'
, etc. - Utilisez des chaînes multilignes. Il n'est pas nécessaire de concaténer plusieurs lignes, utilisez simplement une seule chaîne.
- Utilisez des espaces supplémentaires pour faciliter l'identification du début et de la fin des chaînes. Lorsque les choses deviennent aussi folles, cela vaut la peine de mettre un délimiteur de chaîne sur une ligne tout seul, afin que tout soit facile à aligner.
- Utilisez
REPLACE
au lieu de la concaténation.
J'ai reformaté une partie de votre code en utilisant ces conseils. Stackoverflow ne comprend pas le mécanisme de guillemets alternatif, mais les chaînes devraient mieux paraître dans un bon éditeur 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;
/