Не можем да изпълним DDL в каквато и да е форма на PL/SQL. включително тригери. За да направим това, трябва да използваме динамичен SQL.
Тригерите имат допълнителна бръчка:те се задействат като част от транзакцията и имат ограничение, което ни забранява да издаваме ангажимент в тялото им. В Oracle всяка DDL команда издава два ангажимента, един преди и един след изпълнението на DDL оператора. Така че, за да изпълним DDL в тригер, трябва да използваме autonomous_transaction pragma
, което означава, че DDL се изпълнява в отделна, вложена транзакция.
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;
Автономните транзакции са една от онези конструкции, които са лесни за злоупотреба и саботиране на собствените ни приложения. Във вашия сценарий проблемът е, че CREATE ROLE може да успее в своя балон за транзакция, докато INSERTT в TestTable
не успява; такова е значението на "автономна сделка". Така че все още не ви е гарантирана "съгласуваност между [вашата] таблица и оракул роли едно".
По-добро решение би било да обвиете двата израза в процедурно извикване, вместо да се опитвате да подмамите DML да направи нещо, което не трябва да прави.
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;