Wednesday, 14 February 2024

Oracle "Instead of" triggers - beware of privileges and grants!

Recently I bumped into a problem while dealing with "instead of" triggers in the Oracle database.


The scenario is the following.

In my main schema (let's call it SC1) I created a view named DEMO_STATES_V based on the table DEMO_STATES located in another schema (let's call it SC2).

CREATE OR REPLACE VIEW my_demo_states AS
SELECT st, state_name
FROM sc2.demo_states;

The user SC1 has SELECT privilege granted on the table SC2.DEMO_STATES.

I created an "instead of" trigger on the view DEMO_STATES_V to handle DML operations. 
Currently there is only a dbms output but it is enough to present the problem.

CREATE OR REPLACE TRIGGER my_demo_states_trg
INSTEAD OF INSERT OR UPDATE OR DELETE 
ON my_demo_states
FOR EACH ROW
BEGIN
    dbms_output.put_line('The trigger executes!');
END;
/

I tried to insert the record into the view and I'm expecting to get the dbms output written.

INSERT INTO my_demo_states (st, state_name)
VALUES ('SI', 'Slovenia');

But...

Instead of the trigger execution and dbms output produced I got an error!

ORA-01031: insufficient privileges
Seems that the database checked insert privileges BEFORE executing the trigger!
And while user SC1 does not have the insert privilege granted... an error occurred.

Honestly, I haven't expected that. I mean, if I have the "instead of" trigger created, why would database check any DML privileges on the underlying table? The "instead of" trigger is going to handle eventual DML operations... and grants should be checked for the PL/SQL code in the trigger body.


Another but... there is an override. 💪

If You modify the SELECT statement for the view object and implement UNION ALL from DUAL with "1=2" condition... so that actually no record is added to the original result set from the first part of the select statement... then everything works! For example:

CREATE OR REPLACE VIEW my_demo_states AS
SELECT st, state_name
FROM dome_ms1.demo_states
UNION ALL
SELECT null, null
FROM dual
WHERE 1=2;

No privileges are checked and the trigger executes flawlessly!


No comments:

Post a Comment