Nemůžeme nativně spustit DDL v žádné formě PL/SQL. včetně spouštěčů. K tomu potřebujeme použít dynamické SQL.
Spouštěče mají další vrásku:jsou spouštěny jako součást transakce a mají omezení, které nám zakazuje vydat potvrzení v jejich těle. V Oracle každý příkaz DDL vydá dvě potvrzení, jedno před a jedno po provedení příkazu DDL. Abychom mohli spustit DDL ve spouštěči, musíme použít autonomous_transaction pragma
, což znamená, že DDL běží v samostatné, vnořené transakci.
create or replace TRIGGER TestTrigger
BEFORE INSERT ON TestTable
REFERENCING OLD AS OLD NEW AS NEW
FOR EACH ROW
declare
pragma autonomous_transaction;
BEGIN
execute immediate 'create role '|| :New.RoleName;
END;
Autonomní transakce jsou jedním z těch konstrukcí, které lze snadno zneužít a sabotovat naše vlastní aplikace. Ve vašem scénáři je zádrhel v tom, že CREATE ROLE může uspět ve své transakční bublině, zatímco INSERTT do TestTable
selže; takový je význam „autonomní transakce“. Stále tedy nemáte zaručeno „soudržnost mezi [vaší] tabulkou a rolemi orákula jedna“.
Lepším řešením by bylo zabalit oba příkazy do procedurálního volání, než se pokoušet oklamat DML, aby udělal něco, co dělat nemá.
create or replace procedure create_role
( p_role_name in user_roles.role%type
, p_desc in testtable.description%type )
is
pragma autonomous_transaction;
begin
insert into testtable
( id, creationdate, rolename, description)
values
( some_seq.nextval, sysdate, p_role_name, p_desc );
execute immediate 'create role '|| p_role_name;
end;