Delete latest DML action - sql

I have a trigger that prevents any users that is not me from doing DML injections, whoever tries get the error message "Sorry, you are not allowed to do this"
However my trigger shows this message, but still goes ahead with the code that the user sent. Is there any way to prevent this from happening, ignoring the statement, or deleting the most recent transaction?
Sidenote: I know, using a trigger for this is probably not the way to go, but please ignore this, I'm trying to learn, and right now I'm learning triggers.
Thank you
create or replace trigger my_ex
before insert or update or delete on kund
declare
my_ex exception;
begin
if user not in ('me') then raise my_ex;
end if;
exception
When only_boss then raise_application_error(-20009,'Illegal activity!');
rollback;
end;
/

Your exception must be declared like this:
my_ex EXCEPTION;
PRAGMA EXCEPTION_INIT(my_ex, -20001);
Then user names in Oracle are capital by default, i.e. you should write
if user not in ('ME') then
raise my_ex;
end if;

Related

Postgres: How to prevent anyone from updating a table?

I've been trying to stop any user from updating a table
I tried
REVOKE UPDATE ON TABLE NYAidCrimeMean FROM CURRENT_USER;
but when I try to update the table it still goes through, any pointers?
Well, I do not particular like triggers, but they have their uses. If you cannot find all the previous grants, you can get close here with one. See demo.
create or replace function no_no_no()
returns trigger
language plpgsql
as $$
begin
raise exception 'Cannot update table %s.', tg_table_name;
return null;
end;
$$;
create trigger No_no_no_NYAidCrimeMeanA
before update on NYAidCrimeMean
for each statement
execute function no_no_no();
If you really want to lock it down change before update to before insert or update or delete or truncate.
Of course a superuser can disable the trigger, then do whatever they want, but eventually get to where you must trust someone at some point.
The solution is as trivial as it is obvious: don't use superusers for anything but administative tasks.

Postgres: Save rows from temp table before rollback

I have a main procedure (p_proc_a) in which I create a temp table for logging (tmp_log). In the main procedure I call some other procedures (p_proc_b, p_proc_c). In each of these procedures I insert data into table tmp_log.
How do I save rows from tmp_log into a physical table (log) in case of exception before rollback?
create procedure p_proc_a
language plpgsql
as $body$
begin
create temp table tmp_log (log_message text) on commit drop;
call p_proc_b();
call p_proc_c();
insert into log (log_message)
select log_message from tmp_log;
exception
when others then
begin
get stacked diagnostics
v_message_text = message_text;
insert into log (log_message)
values(v_message_text);
end;
end;
$body$
What is a workround to save logs into a table and rollback changes from p_proc_b and p_proc_c?
That is not possible in PostgreSQL.
The typical workaround is to use dblink to connect to the database itself and write the logs via dblink.
I found three solutions to store data within a transaction (im my case - for debugging propose), and still be able to see that data after rollback-ing the transaction
I have a scenario where inside, I use following block, so it may not apply to your scenario
DO $$
BEGIN
...
ROLLBACK;
END;
$$;
Two first solutions are suggested to me in the Postgres slack, and the other I tried and found after talking with them, a way that worked in other db.
Solutions
1 - Using DBLink
I don't remember how it was done, but you import some libraries and then connect to another db, and use the other DB - which maybe can support to be this db - which seem to be not affected by transactions
2 - Using COPY command
Using the
COPY (SELECT ...) TO PROGRAM 'psql -c "COPY xyz FROM stdin"'
BTW I never used it, and it seems that it requires Super User(SU) permission in Unix. And god knows how it is used, or how it output data
3 - Using Sub-Transactions
In this way, you use a sub-transaction (which I'm not sure it it's correct, but it must be called Autonomous transactions) to commit the result you want to keep.
In my case the command looks like this:
I used a Temp Table, but it seems (I'm not sure) to work with an actual table as well
CREATE TEMP TABLE
IF NOT EXISTS myZone AS
SELECT * from public."Zone"
LIMIT 0;
DO $$
BEGIN
INSERT INTO public."Zone" (...)VALUES(...);
BEGIN
INSERT INTO myZone
SELECT * from public."Zone";
commit;
END;
Rollback;
END; $$;
SELECT * FROM myZone;
DROP TABLE myZone;
don't ask what is the purpose of doing this, I'm creating a test scenario, and I wished to track what I did until now. since this block did not support SELECT of DQL, I had to do something else, and I wanted a clean set of report, not raising errors
According to www.techtarget.com:
*Autonomous transactions allow a single transaction to be subdivided into multiple commit/rollback transactions, each of which
will be tracked for auditing purposes. When an autonomous transaction
is called, the original transaction (calling transaction) is
temporarily suspended.
(This text was indexed by google and existed on 2022-10-11, and the website was not opened due to an E-mail validation issue)
Also this name seems to be coming from Oracle, which this article can relate
EIDTED:
Removing solution 3 as it won't work
POSTGRES 11 Claim to support Autonomous Transactions but it's not what we may expect...
For this functionality Postgres introduced the SAVEPOINT:
SAVEPOINT <name of savepoint>;
<... CODE ...>
<RELEASE|ROLLBACK> SAVEPOINT <name of savepoint>;
Now the issue is:
If you use nested BEGIN, the COMMIT Inside the nested code can COMMIT everything, and the ROLLBACK in the outside block will do none (Not rolling back anything that happened before COMMIT of inner
If you use SAVEPOINT, it is only used to rollbacks part of the code, and even if you COMMIT it, the ROLLBACK in the outside block will rollback the SAVEPOINT too

Is trigger in Oacle the part of request?

I use Spring Repository, And Oracle DB.
I have a table and trigger that fire on insert/update/delete. If I execute some insert/delete/update against the table and trigger got an SQL error (locked resources or something else) will the Repository method got an exception? Or Oracle trigger executes as separated part of insert/delete/update statements?
I don't know Spring Repository, but I do know that in - for example: Oracle Forms, Application Express, Reports - trigger error propagates all the way up. Everything stops in that case.
Suppose that I have a form and enter some data. Database trigger fires and tries to do whatever it does, and it fails with raise_application_error. Nothing gets completed, and I see an error in my form, e.g. "ORA-20001: my custom error".
Therefore, I presume that you'd experience the same in Spring Repository. After all, wouldn't cost much to test it, right? I would if I could, but I can't so - do it yourself.
Your Spring Repository will be error out when you trying to insert data into table. Our DML command will not performed if there is any error in our associated trigger.
Mostly i use DML in my PLSQL procedure for insert and use GET_LOCKED_TRANSACTION() procedure to check if any resource is busy.
FUNCTION GET_LOCKED_TRANSACTION
(
P_WIP_ENTITY_ID IN NUMBER,
P_PRODUCTION_NOTE_NUMBER IN NUMBER
) RETURN BOOLEAN IS
ROW_LOCKED EXCEPTION;
PRAGMA EXCEPTION_INIT(ROW_LOCKED, -54);
BEGIN
/* cURSOR WITH nOWAIT Attribute */
FOR CC IN (SELECT *
FROM myTable
WHERE WIP_ENTITY_ID = P_WIP_ENTITY_ID
FOR UPDATE NOWAIT) LOOP
NULL;
END LOOP;
RETURN FALSE;
EXCEPTION
WHEN ROW_LOCKED THEN
RETURN TRUE;
END GET_LOCKED_TRANSACTION;

Exception to handle unpermitted DML-operation

I'm trying to hinder a user who is not me from performing DML-operations on a table. I'm using a trigger but have some issues with the syntax. It is the "if user is not 'me' part that troubles me. Also, is stating "rollback;" enough to undo the operation? Thanks!
create or replace trigger only_me_ex
before insert or update or delete on table
for each row
declare
only_me_ex exception;
begin
if user is not 'me' then
raise only_boss exception;
end if;
exception
when only_me_ex then
raise_appication_error(-200001,'Not permitted!');
rollback;
end;
/
In your code you use 'USER' keyword, which is actually schema from which is operation performed. E.g. SCOTT is owner of emp table. If you log in as SCOTT an perform update on emp table, the USER as used in your trigger is SCOTT. If you log in as SYS and perform DML on table USER will be SYS. To sum it up:
You don't need trigger like this, you need to grant insert, update, delete privileges on this table only to those users who ought to be allowed to.
In fact rather than schema(user) you may need to know operation system user:
SYS_CONTEXT('USERENV','OS_USER')
EDIT: based on your comment that this is for academic purpose I made changes to your trigger, so it now compiles and works (I stick to your method of declaring exception, raising it and handle it as rerising an application error, which doesn't make much sense to me, but nevermind)
create table my_table (id number)
/
create or replace trigger only_me_ex
before insert or update or delete on my_table
declare
only_me_ex exception;
begin
if user!='TESTUSER' then
raise only_me_ex ;
end if;
exception
when only_me_ex then
raise_application_error(-20001,'Not permitted!');
end;
/
Note that I changed your trigger from level row trigger to statement trigger because it needs to be executed only once and I omitted rollback keyword which is not needed because there will not be anything to rollback (unless you want to rollback some previous operation in transaction);
if user not in ('testuser') then raise not_a_chance;
solved it

No data found in trigger

I have a problem with my trigger. It returns "no data found" and i don't know how to resolve it. Can you help me ?
create or replace
TRIGGER nb_action
AFTER INSERT ON Message
FOR EACH ROW
DECLARE
vAuteur integer;
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
SELECT id_auteur INTO vAuteur FROM Message where id_message = :new.id_message;
UPDATE Utilisateur SET nb_action=nb_action+1 where id_utilisateur=vAuteur;
END ;
Do not use autonomous transactions in normal code. The only time that autonomous transactions are really appropriate are cases when you want to write data to a log table whether or not the underlying action commits. For example, if you want to log an error, rollback the transaction, and raise the exception, you probably don't want the log message to be rolled back. You should absolutely never use an autonomous transaction to work around a mutating table exception which is, I assume, the reason you used an autonomous transaction here since the query against the Message table would raise a mutating table exception if it was not in an autonomous transaction.
Fortunately, in this case, there is no need to query the table on which the trigger is defined and no need to use an autonomous transaction. Simply
create or replace trigger nb_action
AFTER INSERT ON Message
FOR EACH ROW
BEGIN
UPDATE Utilisateur
SET nb_action=nb_action+1
where id_utilisateur=:new.id_auteur;
END ;
Since you have PRAGMA AUTONOMOUS_TRANSACTION; in that trigger it means that it can't see the row just inserted because it is in a different not yet committed transaction thus your SELECT doesn't return any data...
try
create or replace
TRIGGER nb_action
AFTER INSERT ON Message
FOR EACH ROW
DECLARE
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
UPDATE Utilisateur SET nb_action=nb_action+1 where id_utilisateur=:new.id_auteur;
END ;