Non possiamo eseguire nativamente DDL in nessuna forma di PL/SQL. compresi i trigger. Per farlo abbiamo bisogno di usare SQL dinamico.
I trigger hanno un'ulteriore ruga:vengono attivati come parte della transazione e hanno una limitazione che ci vieta di emettere un commit all'interno del loro corpo. In Oracle, qualsiasi comando DDL emette due commit, uno prima e uno dopo l'esecuzione dell'istruzione DDL. Quindi, per eseguire DDL in un trigger dobbiamo usare il autonomous_transaction pragma
, il che significa che il DDL viene eseguito in una transazione nidificata separata.
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;
Le transazioni autonome sono uno di quei costrutti che sono facili da usare in modo improprio e sabotare le nostre stesse applicazioni. Nel tuo scenario l'inconveniente è che CREATE ROLE può avere successo nella sua bolla di transazione mentre INSERTT in TestTable
non riesce; tale è il significato di "transazione autonoma". Quindi non ti è ancora garantita la "coerenza tra il [tuo] tavolo e i ruoli dell'oracolo uno".
Una soluzione migliore sarebbe racchiudere entrambe le istruzioni in una chiamata procedurale, piuttosto che tentare di indurre DML a fare qualcosa che non dovrebbe fare.
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;