Question

I have a separate table with some data and I would like to a create a new role each time a new row is inserted in that table.

I created the following trigger:

create or replace 
TRIGGER TestTrigger
BEFORE INSERT ON TestTable
REFERENCING OLD AS OLD NEW AS NEW 

FOR EACH ROW BEGIN 
    create role :New.RoleName;
END;

but the trigger doesn't compile. I have the error: PLS-00103: PLS-00103: Encountered the symbol "CREATE" when expecting one of the following: ( begin case declare exit for goto if loop mod null pragma raise return select update while with << continue close current delete fetch lock insert open rollback savepoint set sql execute commit forall merge pipe purge

Is that possible ?

Was it helpful?

Solution

We cannot natively execute DDL in any form of PL/SQL. including triggers. To do that we need to use dynamic SQL.

Triggers have an additional wrinkle: they are fired as part of the transaction, and they have a limitation that forbids us from issuing a commit inside their body. In Oracle, any DDL command issues two commits, one before and one after the DDL statement is executed. So, to execute DDL in a trigger we must use the autonomous_transaction pragma, which means the DDL runs in a separate, nested transaction.

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;

Autonomous transaction are one of those constructs which are easy for us to misuse and sabotage our own applications. In your scenario the snag is that the CREATE ROLE can succeed in its transaction bubble whilst the INSERTT into TestTable fails; such is the meaning of "autonomous transaction". So you are still not guaranteed "coherence between [your] table and oracle roles one".

A better solution would be to wrap both statements into a procedural call, rather than attempting to trick DML into doing something it is not supposed to do.

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; 
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top