Vi kan ikke indbygget udføre DDL i nogen form for PL/SQL. inklusive triggere. For at gøre det skal vi bruge dynamisk SQL.
Triggere har en ekstra rynke:de affyres som en del af transaktionen, og de har en begrænsning, der forbyder os at udstede en commit inde i deres krop. I Oracle udsteder enhver DDL-kommando to commits, en før og en efter, at DDL-sætningen er udført. Så for at udføre DDL i en trigger skal vi bruge autonomous_transaction pragma
, hvilket betyder, at DDL kører i en separat, indlejret transaktion.
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 transaktioner er en af de konstruktioner, som er nemme for os at misbruge og sabotere vores egne applikationer. I dit scenarie er ulempen, at OPRET ROLLEN kan lykkes i sin transaktionsboble, mens INSERTT ind i TestTable
fejler; sådan er betydningen af "autonom transaktion". Så du er stadig ikke garanteret "sammenhæng mellem [dit] bord og orakelroller en".
En bedre løsning ville være at pakke begge udsagn ind i et procedureopkald i stedet for at forsøge at narre DML til at gøre noget, den ikke skal gøre.
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;