Nie możemy natywnie wykonać DDL w jakiejkolwiek formie PL/SQL. w tym wyzwalacze. Aby to zrobić, musimy użyć dynamicznego SQL.
Wyzwalacze mają dodatkową zmarszczkę:są odpalane w ramach transakcji i mają ograniczenie, które zabrania nam wydawania commitów wewnątrz ich ciała. W Oracle każde polecenie DDL wydaje dwa zatwierdzenia, jeden przed i jeden po wykonaniu instrukcji DDL. Tak więc, aby wykonać DDL w wyzwalaczu, musimy użyć autonomous_transaction pragma
, co oznacza, że DDL działa w oddzielnej, zagnieżdżonej transakcji.
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;
Transakcje autonomiczne to jedna z tych konstrukcji, które są dla nas łatwe do nadużycia i sabotowania własnych aplikacji. W twoim scenariuszu haczyk polega na tym, że funkcja CREATE ROLE może odnieść sukces w swojej bańce transakcyjnej, podczas gdy WSTAWIĆ do TestTable
zawodzi; takie jest znaczenie „transakcji autonomicznej”. Więc nadal nie masz gwarancji „spójności między [twój] stołem a rolą wyroczni jeden”.
Lepszym rozwiązaniem byłoby zawinięcie obu instrukcji w wywołanie proceduralne, zamiast próbować nakłonić DML do zrobienia czegoś, czego nie powinno się robić.
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;