Vi kan inte köra DDL i någon form av PL/SQL. inklusive triggers. För att göra det måste vi använda dynamisk SQL.
Triggers har ytterligare en rynka:de avfyras som en del av transaktionen och de har en begränsning som förbjuder oss att utfärda ett åtagande inuti deras kropp. I Oracle utfärdar alla DDL-kommandon två commits, en före och en efter att DDL-satsen exekveras. Så för att exekvera DDL i en trigger måste vi använda pragman autonomous_transaction pragma
, vilket innebär att DDL körs i en separat, kapslad 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;
Autonoma transaktioner är en av de konstruktioner som är lätta för oss att missbruka och sabotera våra egna applikationer. I ditt scenario är problemet att CREATE ROLE kan lyckas i sin transaktionsbubbla medan INSERTT in i TestTable
misslyckas; sådan är innebörden av "autonom transaktion". Så du är fortfarande inte garanterad "koherens mellan [ditt] bord och orakelroller ett".
En bättre lösning skulle vara att slå in båda påståendena i ett procedursamtal, snarare än att försöka lura DML att göra något den inte är tänkt att göra.
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;