How to get this data permission configuration on Oracle? - oracle

I'm writing an application and I would like to know whether is it possible to get this data permission configuration on the Database side (Oracle) not the application side.
It's basically related to some tables that have to store historical data that can not be edited the day after they were typed...
Table : X
Fields :
WhatEver as varchar2
MyDate as DateTime
For each row, if (Current Date = MyDate), editing is allowed. Otherwise, No.
Is that possible please ? Am I required to use Oracle Label Security ?
I'm looking for something that can be managed as Access Rights (Grant/Revoke...) The usage would be that the administrator can Create, Grant or Revoke such a permission to a user or a role.
Thanks.

A row level trigger should do the trick.
create or replace trigger my_trigger
before update on my_table
for each row
begin
-- Only compare the date part (trunc removes the time)
if trunc(:old.mydate)!=trunc(sysdate)
then raise_application_error(-20000,'Updates only allowed on the day of entry');
end if;
end;
Of course, entries added just before midnight have a very short edit time.
Also, you should somehow disable the possibility to update the mydate field. Some extra lines in the trigger will take care of that.

Related

PL/SQL Trigger not working - issue with setting variable

my trigger doesn't work, when I try to update a query. Any ideas why?
I feel like it is related to the WHERE conditions when I try to set variables.
I tried to do it without the WHERE conditions, but it still didn't work.
Any ideas why? Thank You!
CREATE OR REPLACE TRIGGER SYSTEM.Product_Price_Check
BEFORE UPDATE ON SYSTEM.product FOR EACH ROW
DECLARE
min_price NUMBER(19,4);
new_price NUMBER(19,4);
BEGIN
SELECT (StandardCost*1.2)
INTO min_price
FROM SYSTEM.product
WHERE ProductID = :new.ProductID;
SELECT ListPrice
INTO new_price
FROM SYSTEM.product
WHERE ProductID = :new.ProductID;
IF new_price < min_price THEN
ROLLBACK;
--DBMS_OUTPUT.PUT_LINE('the price can’t be below '||CAST(min_price as VARCHAR(25)));
--RAISE VALUE_ERROR;
--ELSE
--DBMS_OUTPUT.PUT_LINE('Price was successfully changed');
END IF;
END;
I suppose this is a homework assignment and you have been told to use a trigger. Long years on this site have taught me that teachers love setting assignments which demand the misuse of triggers.
In real life the only correct way to enforce such a rule is with a check constraint:
alter table product add constraint price_check
check (standard_cost * 1.2 >= min_price)
Show your error.
Probably your trigger is mutating
The session that issued the triggering statement cannot query or modify a mutating table. This restriction prevents a trigger from seeing an inconsistent set of data.
As others have pointed out, you should not be creating objects such as tables or triggers in the SYSTEM schema. Create yourself a user, grant it the necessary privileges (good practice), and use that user and its schema for development purposes.
Next - in a row triggers (one with FOR EACH ROW in it) you cannot access the table upon which the trigger is defined, which in this case is the PRODUCT table. Fortunately, you don't really need to. The values you want are already in the :OLD or :NEW pseudo-rows - I'm guessing here that you really want to use the :NEW values:
CREATE OR REPLACE TRIGGER PRODUCT_PRICE_CHECK
BEFORE UPDATE ON PRODUCT
FOR EACH ROW
DECLARE
nMin_price NUMBER := :NEW.STANDARD_COST * 1.2;
BEGIN
IF :NEW.LISTPRICE < nMin_price THEN
DBMS_OUTPUT.PUT_LINE('List price can’t be below '|| nMin_price);
RAISE VALUE_ERROR;
END PRICE_CHECK;
Also, you can't execute a ROLLBACK or COMMIT in a trigger - Oracle doesn't allow this to happen.

How can Time and Date be automatically updated when a data is inserted or updated in oracle?

I want that every time a data is input in oracle table the date and time must automatically be updated in one of the column named 'CREATION_DATE'.
Setting default value of SYSDATE is more efficient than a trigger. As helpc mentioned, a default value can be overridden if NULL is explicitly provided in the INSERT. If you don't intend to pass date time thru application at all, you can define the column as NOT NULL with a default as sysdate .
A trigger will do what you want. I think something like this is what you are looking for:
CREATE OR REPLACE TRIGGER date_trigger
AFTER INSERT ON your_table
FOR EACH ROW
WHEN (new.your_table> 0)
BEGIN
:NEW.CREATION_DATE:= SYSDATE;
END;
/
Depending on your needs I usually like to add both a create_date and an update_date column to pick up timestamps for changes that may occur later.

Make column readonly on specific condition oracle

I am trying to create some kind of trigger to prevent a row being edited if it is after today's date (will use SYSDATE to get that).
I am unsure about how to do this as I am new to PL/SQL and would think perhaps some kind of package that gets the date using a cursor then uses a function to return a boolean to a procedure which then somehow stops the DML statement from firing?
Thanks in advance
Obviously you need a date column as your target. Truncating SYSDATE will give you midnight. Consequently if a truncated SYSDATE is greater than another date it must be at least the next day.
Raising an application error will cause the update to fail. Note that if you're updating multiple rows a single failure will rollback all the changes.
create or replace trigger your_trg
before update on your_table
for each row
begin
if trunc(sysdate) > :old.whatever_date then
raise_application_error(-20000, 'It is too late to change this record');
end if;
end;
the solution you are looking for is VPD Column masking.
mainly used for security purposes, VPD enables you to define row/colums level rules for data access and display.

Trying to create a trigger that prevents updates based on value from another table

I am trying to prevent users from updating one table based on a date value from another table.
Table A contains rows that I would like to make un editable if a date value in the Table B is older than sysdate.
I need to somehow tell the trigger to check the row and use a foreign key in Table A's row to query its corresponding rows in Table B and then do this:
raise_application_error(-20000, 'It is too late to change this record');
Thank You
Assuming this is a homework assignment, you'd want something like this (I'm guessing at table structures and cardinalities since you don't specify).
CREATE OR REPLACE TRIGGER trigger_name
AFTER UPDATE ON a
FOR EACH ROW
DECLARE
l_dt_b b.dt_col%type;
BEGIN
SELECT dt_col
INTO l_dt_b
FROM b
WHERE b.b_key = :new.b_key;
IF( l_dt_b < sysdate )
THEN
RAISE_APPLICATION_ERROR( -20001, 'Too late' );
END IF;
END;
If this is for a real system, however, trigger-based validation is problematic. It is not safe in a multi-user system, for example. In session 1, I may have modified the row in B but not yet committed the change. You can then query the row in session 2, see the old value, and allow the UPDATE. We can both commit our changes and nothing will detect that we have data in an invalid state.

Is it possible to configure Oracle session/connection to automatically uppercase strings?

Does anyone know if it's possible to configure an Oracle session or connection so that every string that gets persisted is automatically uppercased?
For example, if I invoke a SQL like this: "INSERT INTO STUDENT (name) VALUES ('john doe')"
The information in my table would be persisted like this:
STUDENT
--------------------
ID | 1
NAME | JOHN DOE
I've checked this entry but couldn't find anything like this: http://docs.oracle.com/cd/B19306_01/server.102/b14225/ch3globenv.htm#sthref186
Thanks!
There is no session-level configuration parameter for that, no.
You could write a trigger on the STUDENT table that would automatically store the data in uppercase but you'd need to do that for every table.
CREATE TRIGGER trg_student
BEFORE INSERT ON student
FOR EACH ROW
BEGIN
:new.name := upper( :new.name );
END;
Depending on the problem you are trying to solve, you could potentially set your session's NLS settings to ignore case sensitivity so that the string 'John Doeis considered to be equal to the stringJOHN DOE`. The options, limitations, and downsides to this will vary with the specific version of Oracle.

Resources