DBMS_UTILITY.EXEC_DDL_STATEMENT
hanya andal menjalankan DDL. Jika Anda mencoba menjalankannya dengan blok PL/SQL, itu akan gagal secara diam-diam dan tidak menjalankan apa pun.
Ini dapat ditunjukkan dengan menjalankan blok PL/SQL yang seharusnya gagal. Kode di bawah harus menghasilkan ORA-01476: divisor is equal to zero
. Tapi malah tidak menghasilkan apa-apa.
begin
[email protected](
q'[declare v_test number; begin v_test := 1/0; end;]'
);
end;
/
Gunakan prosedur sementara untuk menjalankan blok PL/SQL dari jarak jauh. Buat prosedur dengan DBMS_UTILITY.EXEC_DDL_STATEMENT
lalu panggil dengan SQL dinamis asli.
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
Saya pikir perilaku ini adalah bug. Oracle seharusnya membuat kesalahan daripada tidak melakukan apa-apa.
Selamat datang di neraka gabungan. String menjadi berantakan saat disematkan sedalam 4 level. Namun ada beberapa hal yang dapat Anda lakukan untuk membuat hidup lebih mudah:
- Gunakan mekanisme kutipan alternatif bersarang. Misalnya,
q'[ ... ]'
, di dalamq'< ... >'
, dll. - Gunakan string multi-baris. Tidak perlu menggabungkan beberapa baris, cukup gunakan satu string.
- Gunakan spasi ekstra untuk membantu mengidentifikasi awal dan akhir string. Saat semuanya menjadi gila, ada baiknya menempatkan pembatas string pada baris dengan sendirinya, sehingga semuanya mudah untuk disejajarkan.
- Gunakan
REPLACE
bukannya penggabungan.
Saya memformat ulang bagian dari kode Anda menggunakan kiat-kiat itu. Stackoverflow tidak memahami mekanisme kutipan alternatif, tetapi string akan terlihat lebih baik dalam editor SQL Oracle yang baik.
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;
/