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'< ... >'
内 、など。 - 複数行の文字列を使用します。複数の行を連結する必要はなく、1つの文字列を使用するだけです。
- 余分な間隔を使用して、文字列の開始と終了を識別しやすくします。物事がこれほどおかしくなったときは、すべてを簡単に並べられるように、文字列区切り文字をすべて1行に配置する価値があります。
-
REPLACE
を使用する 連結の代わりに。
これらのヒントを使用して、コードの一部を再フォーマットしました。 Stackoverflowは代替の引用メカニズムを理解していませんが、文字列は優れたOracleSQLエディターで見栄えが良くなるはずです。
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;
/