DBMS_UTILITY.EXEC_DDL_STATEMENT
tylko niezawodnie uruchamia DDL. Jeśli spróbujesz uruchomić go z blokiem PL/SQL, po cichu zawiedzie i nie uruchomi niczego.
Można to zademonstrować, uruchamiając blok PL/SQL, który oczywiście powinien się nie powieść. Poniższy kod powinien generuj ORA-01476: divisor is equal to zero
. Ale zamiast tego nic nie robi.
begin
[email protected](
q'[declare v_test number; begin v_test := 1/0; end;]'
);
end;
/
Użyj tymczasowej procedury, aby zdalnie uruchomić blok PL/SQL. Utwórz procedurę za pomocą DBMS_UTILITY.EXEC_DDL_STATEMENT
a następnie wywołaj go za pomocą natywnego dynamicznego 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
Myślę, że to zachowanie jest błędem. Oracle powinno zgłosić błąd zamiast po prostu nic nie robić.
Witaj w piekle konkatenacji. Struny stają się bałaganem, gdy są osadzone na 4 poziomy. Jest jednak kilka rzeczy, które możesz zrobić, aby ułatwić życie:
- Użyj zagnieżdżonego mechanizmu cytowania alternatywnego. Na przykład
q'[ ... ]'
, wewnątrzq'< ... >'
itp. - Użyj ciągów wielowierszowych. Nie ma potrzeby łączenia wielu linii, wystarczy użyć jednego ciągu.
- Użyj dodatkowych odstępów, aby zidentyfikować początek i koniec ciągów. Kiedy sprawy przybierają taki szalony obrót, warto postawić sam ogranicznik ciągu w linii, aby wszystko było łatwe do wyrównania.
- Użyj
REPLACE
zamiast konkatenacji.
Korzystając z tych wskazówek, ponownie sformatowałem część kodu. Stackoverflow nie rozumie alternatywnego mechanizmu cytowania, ale ciągi powinny wyglądać lepiej w dobrym edytorze 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;
/