We kunnen DDL in geen enkele vorm van PL/SQL native uitvoeren. inclusief triggers. Om dat te doen, moeten we dynamische SQL gebruiken.
Triggers hebben een extra rimpel:ze worden geactiveerd als onderdeel van de transactie en ze hebben een beperking die ons verbiedt om een commit in hun lichaam uit te geven. In Oracle geeft elk DDL-commando twee commits uit, één voor en één nadat de DDL-instructie is uitgevoerd. Dus om DDL in een trigger uit te voeren, moeten we het autonomous_transaction pragma
gebruiken , wat betekent dat de DDL in een afzonderlijke, geneste transactie wordt uitgevoerd.
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;
Autonome transacties zijn een van die constructies waarmee we gemakkelijk onze eigen applicaties kunnen misbruiken en saboteren. In jouw scenario is het probleem dat de CREATE ROL kan slagen in zijn transactiebubbel terwijl de INSERTT in TestTable
mislukt; dat is de betekenis van "autonome transactie". U bent dus nog steeds niet verzekerd van "coherentie tussen [uw] tafel- en orakelrollen één".
Een betere oplossing zou zijn om beide verklaringen in een procedurele oproep te stoppen, in plaats van te proberen DML te misleiden om iets te doen wat het niet zou moeten doen.
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;