Prevent Drop View in Oracle - sql

How to prevent a user from not dropping a view even he/she has previlige to do so? I have a view being used by an application. However, it was dropped by a user a couple times. Is there something like REVOKE DROP ANY VIEW? Do I have to use a trigger for that?

A trigger might help. Here's an example.
First, a few objects to be dropped:
SQL> create table test as select * From emp where 1 = 2;
Table created.
SQL> create or replace view v_dept as select * From dept;
View created.
SQL>
I don't want to allow V_DEPT to be dropped, so:
SQL> create or replace trigger trg_drop
2 before drop on schema
3 declare
4 l_name varchar2(30);
5 begin
6 select ora_dict_obj_name
7 into l_name
8 from dual;
9 if l_name = 'V_DEPT' then
10 raise_application_error(-20001, 'Forbidden');
11 end if;
12 end;
13 /
Trigger created.
Testing:
SQL> drop view v_dept;
drop view v_dept
*
ERROR at line 1:
ORA-00604: error occurred at recursive SQL level 1
ORA-20001: Forbidden
ORA-06512: at line 8
SQL> drop table test;
Table dropped.
SQL>

Related

How can I get the table name in a Oracle trigger function?

How can I get the table name inside trigger function?
Something similar to TG_TABLE_NAME in Postgres, like this
Oracle 10g or above.
That's user_triggers view (if I understood the question correctly).
SQL> create table test (id number, name varchar2(20));
Table created.
SQL> create or replace trigger trg_test
2 before insert on test
3 for each row
4 begin
5 null;
6 end;
7 /
Trigger created.
SQL> select trigger_name, table_name from user_triggers;
TRIGGER_NAME TABLE_NAME
------------------------------ ------------------------------
TRG_TEST TEST --> this is the one I've just created
TRG_AIUD_EMP EMPLOYEES
SQL>

trigger in oracle that ensures that the value of ExpDate from the table ExpIt is less than or equal to the ERSubDate from the ExpReport

I am trying to create a trigger in oracle that ensures that the value of ExpDate from the table ExpIt is less than or equal to the ERSubDate from the ExpReport on INSERT and UPDATE statements that change the ExpDate in the ExpIt table.
When ran in the command prompt, the following comes up
warning: Trigger created with compilation errors.
Here is what I have tried so far, where am I going wrong?
Thank you in advance.
CREATE OR REPLACE TRIGGER Expense_Date
BEFORE INSERT OR UPDATE OF ExpDate
ON ExpIt
FOR EACH ROW
DECLARE
anExpDate ExpIts.ExpDate%TYPE;
anERSubDate ExpReport.ERSubDate%TYPE;
DateError EXCEPTION;
ExMessage VARCHAR(200);
BEGIN
SELECT ExpDate, ERSubDate
INTO anExpDate, anERSubDate
FROM ExpIt, ExpReport
WHERE ExpIt.ExpDate = :NEW.ExpDate;
IF anExpDate <= anERSubDate THEN
RAISE DateError;
END IF;
EXCEPTION
WHEN DateError THEN
ExMessage := ExMessage || 'Expense Date is Incorrect as it is after the Expense Report Submition date' ||
to_date(anExpDate);
raise_application_error(-20001, ExMessage);
END;
/
Before you go too far down this track - be aware that you generally cannot access the table you are triggering on from within the trigger itself.
In your case, your trigger is on EXPIT and you want to query EXPIT. That won't work.
Here's a trivial example of that:
SQL> create table t (x int );
Table created.
SQL> insert into t values (1);
1 row created.
SQL> commit;
Commit complete.
SQL>
SQL> create or replace
2 trigger TRG
3 before insert on T
4 for each row
5 declare
6 blah int;
7 begin
8 select count(*) into blah from t;
9 end;
10 /
Trigger created.
SQL>
SQL> insert into t values (2);
1 row created.
It looks fine, but in reality, there are plenty of cases where it will NOT work
SQL> insert into t
2 select rownum from dual
3 connect by level <= 5;
insert into t
*
ERROR at line 1:
ORA-04091: table MCDONAC.T is mutating, trigger/function may not see it
ORA-06512: at "MCDONAC.TRG", line 4
ORA-04088: error during execution of trigger 'MCDONAC.TRG'
This is a big topic, and more details on the issue and how to work around it are here
https://asktom.oracle.com/pls/apex/asktom.search?file=MutatingTable.html#presentation-downloads-reg

Disable trigger in another db(Oracle)

Can I create a procedure that disables a trigger in another database? I mean, can I disable it with a database link?
I need it for importing data into a data warehouse
Yes, you can do that. Here's how.
In a remote database (called ORCL), I'm creating a table and a trigger:
SQL> create table test (id number);
Table created.
SQL> create or replace trigger trg_test
2 before insert on test
3 for each row
4 begin
5 null;
6 end;
7 /
Trigger created.
Furthermore, in the same (remote) database, I'm creating a procedure which will disable that trigger. It'll use dynamic SQL as you can't execute DDL in PL/SQL just like that:
SQL> create or replace procedure p_disable_trg_test as
2 begin
3 execute immediate 'alter trigger trg_test disable';
4 end;
5 /
Procedure created.
Now, in a local database, I'm creating a database link to the ORCL database:
SQL> create database link dbl_scott_orcl
2 connect to scott
3 identified by tiger
4 using 'orcl';
Database link created.
Does it work?
SQL> select * from dual#dbl_scott_orcl;
D
-
X
Yes, it does. Fine. Now, all you have to do is to call the remote procedure from the local database:
SQL> begin
2 p_disable_trg_test#dbl_scott_orcl;
3 end;
4 /
PL/SQL procedure successfully completed.
SQL>
Let's check the remote database's trigger status:
SQL> select trigger_name, status from user_Triggers where trigger_name = 'TRG_TEST';
TRIGGER_NAME STATUS
------------------------------ --------
TRG_TEST DISABLED
SQL>
DISABLED, as expected.

Select records from table where table name come from another table

We generate tables dynamically Eg. Table T_1, T_2, T_3, etc & we can get that table names from another table by following query.
SELECT CONCAT('T_', T_ID) AS T_NAME FROM T_NAMES WHERE T_KEY = 'ABC';
Now I want to get records from this retrieved table name. What can I do ?
I'm doing like following but that's not working :
SELECT * FROM (SELECT CONCAT('T_', T_ID) AS T_NAME FROM T_NAMES WHERE T_KEY = 'ABC')
FYI : I'm hitting two individual queries as of now though I want to eliminate one and I can not follow cursor/procedure approach due to some limitations.
A procedure which utilizes refcursor seems to be the most appropriate to me. Here's an example:
SQL> -- creating test case (your T_NAMES table and T_1 which looks like Scott's DEPT)
SQL> create table t_names (t_id number, t_key varchar2(3));
Table created.
SQL> insert into t_names values (1, 'ABC');
1 row created.
SQL> create table t_1 as select * from dept;
Table created.
SQL> -- a procedure; accepts KEY and returns refcursor
SQL> create or replace procedure p_test
2 (par_key in varchar2, par_out out sys_refcursor)
3 as
4 l_t_name varchar2(30);
5 begin
6 select 'T_' || t_id
7 into l_t_name
8 from t_names
9 where t_key = par_key;
10
11 open par_out for 'select * from ' || l_t_name;
12 end;
13 /
Procedure created.
OK, let's test it:
SQL> var l_out refcursor
SQL> exec p_test('ABC', :l_out)
PL/SQL procedure successfully completed.
SQL> print l_out
DEPTNO DNAME LOC
---------- -------------- -------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON
SQL>
I could propose to you Dynamic SQL.
First of all, you need to create a cursor. The cursor will iterate by the dynamic tables. Then you could use dynamic SQL to create a query and then execute it.
So example:
https://livesql.oracle.com/apex/livesql/file/content_C81136WLRFYZF8ION6Q57GWE1.html - detailed cursor example.
https://docs.oracle.com/cd/B28359_01/appdev.111/b28370/dynamic.htm#i13057 - dynamic SQL in Oracle

Oracle 9i auto increment trigger/sequence doesnt work

The following SQL, upon being executed on an Oracle 9i server, yields the the error " ORA-04098: trigger 'DBO.WTF_TRIGGER' is invalid and failed re-validation".
DROP TABLE "DBO".WTF;
CREATE TABLE "DBO".WTF
(id NUMBER PRIMARY KEY,
name VARCHAR2(30));
CREATE SEQUENCE "DBO".WTF_sequence
START WITH 1
INCREMENT BY 1;
CREATE OR REPLACE TRIGGER "DBO".WTF_trigger
BEFORE INSERT
ON "DBO".WTF
REFERENCING NEW AS NEW
FOR EACH ROW
BEGIN
SELECT "DBO".WTF_sequence.nextval INTO :NEW.id FROM dual;
END;
INSERT INTO "DBO".WTF (name) VALUES ('asd');
Any ideas?
As APC points out, it would be helpful to do a SHOW ERRORS in SQL*Plus to print out the errors. The code you posted works perfectly for me if I create a DBO user with appropriate privileges.
SQL> conn / as sysdba
Connected.
SQL> create user dbo identified by dbo;
User created.
SQL> grant connect, resource, unlimited tablespace to dbo;
Grant succeeded.
SQL> conn dbo/dbo
Connected.
SQL> DROP TABLE "DBO".WTF;
DROP TABLE "DBO".WTF
*
ERROR at line 1:
ORA-00942: table or view does not exist
SQL>
SQL> CREATE TABLE "DBO".WTF
2 (id NUMBER PRIMARY KEY,
3 name VARCHAR2(30));
Table created.
SQL>
SQL> CREATE SEQUENCE "DBO".WTF_sequence
2 START WITH 1
3 INCREMENT BY 1;
Sequence created.
SQL>
SQL> CREATE OR REPLACE TRIGGER "DBO".WTF_trigger
2 BEFORE INSERT
3 ON "DBO".WTF
4 REFERENCING NEW AS NEW
5 FOR EACH ROW
6 BEGIN
7 SELECT "DBO".WTF_sequence.nextval INTO :NEW.id FROM dual;
8 END;
9 /
Trigger created.
SQL> INSERT INTO "DBO".WTF (name) VALUES ('asd');
1 row created.
SQL> select * from wtf;
ID NAME
---------- ------------------------------
1 asd