First of all I am a newbie to ORACLE and I am just working for a school project.
I want to create a trigger that triggers every time someone else than the user named 'ion' performs a DDL command.
When logged on other user, to have access to Ion's tables I used this command:
alter session set current_schema = ion;
Here is the code:
set serveroutput on;
CREATE OR REPLACE TRIGGER t12
BEFORE CREATE OR DROP OR ALTER ON SCHEMA
BEGIN
dbms_output.put_line('LALA');
IF UPPER(USER) != 'ION' THEN
RAISE_APPLICATION_ERROR(-20022, 'Only Ion can do this');
ELSE
INSERT INTO audit_ion VALUES(SYS.LOGIN_USER, SYS.DATABASE_NAME, SYS.SYSEVENT, SYS.DICTIONARY_OBJ_NAME, SYSDATE);
END IF;
END;
/
alter session set current_schema = ion;
create table dummy(d integer);
And it creates the table, and not even LALA is printed, so it means it doesn't even enter the trigger. How can I do this ?
From my point of view, you should actually REVOKE all privileges you want to prevent by that trigger.
Meanwhile, as of a trigger, you should have probably checked dictionary_obj_owner instead of user.
I don't have your users (and don't feel like creating that ion) so I'm using my own scott and mike.
SQL> show user
USER is "SCOTT"
SQL> CREATE TABLE audit_ion (
2 login_user VARCHAR2(10),
3 database_name VARCHAR2(10),
4 sysevent VARCHAR2(15),
5 dictionary_obj_name VARCHAR2(20),
6 datum DATE
7 );
Table created.
SQL>
SQL> CREATE OR REPLACE TRIGGER t12 BEFORE CREATE OR DROP OR ALTER ON scott.SCHEMA BEGIN
2 dbms_output.put_line('lala');
3 --IF upper(user) != 'SCOTT' THEN
4 IF upper(dictionary_obj_owner) != 'SCOTT' then
5 raise_application_error(-20022, 'Only Scott can do this');
6 ELSE
7 INSERT INTO audit_ion VALUES (
8 sys.login_user,
9 sys.database_name,
10 sys.sysevent,
11 sys.dictionary_obj_name,
12 sysdate
13 );
14
15 END IF;
16 END;
17 /
Trigger created.
SQL>
Testing (still connected as scott):
SQL> create table trg_test (a number);
Table created.
Altering the session:
SQL> alter session set current_schema = mike;
Session altered.
SQL> create table trg_test (a number);
create table trg_test (a number)
*
ERROR at line 1:
ORA-00604: error occurred at recursive SQL level 1
ORA-20022: Only Scott can do this
ORA-06512: at line 5
SQL> alter session set current_schema = scott;
Session altered.
SQL> select * from audit_ion;
LOGIN_USER DATABASE_N SYSEVENT DICTIONARY_OBJ_NAME DATUM
---------- ---------- --------------- -------------------- --------
SCOTT XE CREATE TRG_TEST 05.01.22
SQL>
Kind of works.
Related
I have gone through similar threads but unable to understand the root cause of the error.
I have an Oracle Schema as "PRP".
PRP has one table Named : "MY_TABLE".
PRP has one package Named : "My_PKG" with authid current_user
Package contains following procedure
PROCEDURE CUSTOMER_ORDER_QUERY (
P_REPORT OUT SYS_REFCURSOR
) AS
BEGIN
OPEN P_REPORT FOR SELECT
* from MY_TABLE
END;
When I execute the procedure from the package it gives the error Table or view does not exists.
But when I prefix the schema name to the table in the procedures the cursor executes perfectly.
I have explicitly given privileges on that table to same schema.
from sys users : grant all on prp.MY_TABLE to PRP;
But none helps.
The Package and the table is in same schema.
Please help.
I did what you described; no problems.
Create user prp and grant required privileges:
SQL> connect sys as sysdba
Enter password:
Connected.
SQL> create user prp identified by prp
2 default tablespace users
3 temporary tablespace temp
4 quota unlimited on users;
User created.
SQL> grant create session, create table, create procedure to prp;
Grant succeeded.
Connect as prp, create table and package:
SQL> connect prp/prp
Connected.
SQL> create table my_table as
2 select 1 id, 'Little' name from dual union all
3 select 2 , 'Foot' from dual;
Table created.
SQL> create or replace package my_pkg as
2 procedure customer_order_query (p_report out sys_refcursor);
3 end;
4 /
Package created.
SQL> create or replace package body my_pkg as
2 procedure customer_order_query (p_report out sys_refcursor)
3 as
4 begin
5 open p_report for select * from my_table;
6 end;
7 end;
8 /
Package body created.
Testing:
SQL> var l_rc refcursor
SQL> exec my_pkg.customer_order_query (:l_rc);
PL/SQL procedure successfully completed.
SQL> print l_rc;
ID NAME
---------- ------
1 Little
2 Foot
SQL>
So, yes - it works. If both table and package belong to the same user (reside in the same schema), you don't need any additional privileges as you own both of them.
create table T_XXX
(
DATE_POST VARCHAR2(8) NOT NULL,
DATE_GET DATE DEFAULT TO_DATE(SUBSTR("DATE_POST",1,8),'YYYYMMDD')
);
Error:
ORA-00904:"DATE_POST"
Why does this happen?
My Oracle version is 12c
Nope, that won't work.
But, as you're on 12c, create a virtual column. For example:
SQL> alter session set nls_Date_format = 'dd.mm.yyyy';
Session altered.
SQL> create table test
2 (date_post varchar2(8),
3 date_get date generated always as (to_date(date_post, 'yyyymmdd'))
4 );
Table created.
SQL> insert into test (date_post) values ('20200501');
1 row created.
SQL> select * From test;
DATE_POS DATE_GET
-------- ----------
20200501 01.05.2020
SQL>
It a one of requirement where the client needs there Oracle users do not change his password very soon, so they need to retain at least one day before altering it. So it can not be changed on the same day, where we have to update VERIFY_PASSWORD_FUNCTION code to set a limit minimum password age 1 day.
Append Below Code in "VERIFY_PASSWORD_FUNCTION" Function:
CREATE OR REPLACE FUNCTION "SYS"."VERIFY_PASSWORD_FUNCTION"
(username varchar2,
password varchar2,
old_password varchar2)
RETURN boolean IS
last_change sys.user$.ptime%type;
minimum_age number :=1;
userexist integer;
begin
-- Set minimum password age
select count(*) into userexist from sys.user$ where name=username;
if (userexist != 0) then
select ptime into last_change from sys.user$ where name=username;
if sysdate - last_change < minimum_age then
raise_application_error(-20010, 'Password changed too soon');
END IF;
end if;
end;
/
From the above code you have to append only variables and logic.
Here is A Test Case:
SQL> create user TEST11 identified by asdfhe#24HyrE profile USERS;
User Created.
SQL> alter user test11 identified by asdfhe#24HyrWW;
alter user test11 identified by asdfhe#24HyrWW
*
ERROR at line 1:
ORA-28003: password verification for the specified password failed
ORA-20010: Password changed too soon
SQL>
SQL> select name,ptime from user$ where name='TEST11';
NAME PTIME
------------------------------ ---------
TEST11 08-NOV-18
SQL> update user$ set ptime='03-Nov-18' where name='TEST11';
1 row updated.
SQL> select name,ptime from user$ where name='TEST11';
NAME PTIME
------------------------------ ---------
TEST11 03-NOV-18
SQL> commit;
Commit complete.
SQL> alter user test11 identified by asdfhe#24HyrWW;
User altered.
SQL>
Since we can not change the password within same day so we've updated ptime value to verify and tried again to alter password for Test11 user.
I have created a user (say DROP_PARTITION_USER) to drop partitions of a table. The table is owned by different user (say NORMAL_USER).
Currently, I have granted DROP ANY TABLE and ALTER ANY TABLE privileges to DROP_PARTITION_USER. When DROP_PARTITION_USER executes following statement, it gets executed successfully.
ALTER TABLE SCHEMANAME.TABLENAME DROP PARTITION <PARTITION_NAME> UPDATE GLOBAL INDEXES;
But, DROP ANY TABLE and ALTER ANY TABLE allows DROP_PARTITION_USER to drop and alter any table under any schema [https://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_9013.htm ].
Is there any way in Oracle to restrict drop and alter table under specific schema?
The common way to solve this is to create a procedure owned by NORMAL_USER to drop one of the partitions of one of it's tables.
Then you GRANT EXECUTE on this procedure to DROP_PARTITION_USER.
You'll need no extra privileges.
CREATE OR REPLACE PROCEDURE my_drop_partition (p_table_name VARCHAR2, p_partition_name VARCHAR2)
IS
BEGIN
EXECUTE IMMEDIATE 'ALTER TABLE '||p_table_name||' DROP PARTITION '||p_partition_name;
END my_drop_partition;
/
GRANT EXECUTE ON my_drop_partition TO drop_partition_user;
You can use a DDL trigger to capture such attempts and take whatever action you like. For example
SQL> CREATE OR REPLACE TRIGGER STOP_THAT_STUFF
2 before create or alter or drop on database
3 begin
4 if ora_dict_obj_owner in ('SCOTT') and
5 ora_sysevent in ('DROP','ALTER') and
6 ora_dict_obj_name = 'MY_TABLE'
7 then
8 raise_application_error(-20000,'What the hell are you thinking!!!!');
9 end if;
10 end;
11 /
Trigger created.
SQL>
SQL> conn scott/tiger
Connected.
SQL> create table scott.my_table(x int );
Table created.
SQL> create table scott.my_other_table(x int);
Table created.
SQL> drop table my_other_table;
Table dropped.
SQL> drop table my_table;
drop table my_table
*
ERROR at line 1:
ORA-04088: error during execution of trigger 'SYS.STOP_THAT_STUFF'
ORA-00604: error occurred at recursive SQL level 1
ORA-20000: What the hell are you thinking!!!!
ORA-06512: at line 6
SQL> desc my_table
Name Null? Type
----------------------------------------------------------------------- -------- ----------------
X NUMBER(38)
Error message
CREATE TABLE DEPARTMENT(DID INT,DNAME VARCHAR2(20),DLOC VARCHAR2(20));
INSERT INTO DEPARTMENT VALUES(101,'SRINATH','HINDUPUR');
INSERT INTO DEPARTMENT VALUES(102,'SAINATH','ANANTAPUR');
create or replace PROCEDURE ADD_DEPARTMENT
(P_DID IN DEPARTMENT.DID%TYPE,
P_DNAME IN DEPARTMENT.DNAME%TYPE,
P_DLOC IN DEPARTMENT.DLOC%TYPE,
P_ERROR_MSG OUT VARCHAR2)
IS
BEGIN
INSERT INTO DEPARTMENT(DID,DNAME,DLOC)VALUES(P_DID,P_DNAME,P_DLOC);
COMMIT;
EXCEPTION
WHEN OTHERS THEN
P_ERROR_MSG:=SQLERRM;
END ADD_DEPARTMENT;
iam writing a simple procedure try to excute but it shows object_id:invalid identifier how i can solve
complete procedure execution image
One of your column names may be wrong in the parameter list/insert. Try just using varchar2 for all of them and see if that helps
create or replace PROCEDURE ADD_DEPT2
(P_DEPTNO IN VARCHAR2,
P_DNAME IN VARCHAR2,
P_LOC IN VARCHAR2,
P_ERROR_MSG OUT VARCHAR2)
IS
BEGIN
INSERT INTO DEPT1(DEPTNO,DNAME,LOC)VALUES(P_DEPTNO,P_DNAME,P_LOC);
COMMIT;
EXCEPTION
WHEN OTHERS THEN
P_ERROR_MSG :=SQLERRM;
END ADD_DEPT2;
"it will come same error can be displayed"
No, no it won't. Let's prove it by running the code you posted.
Here is your table:
SQL> CREATE TABLE DEPARTMENT(DID INT,DNAME VARCHAR2(20),DLOC VARCHAR2(20));
Table created.
SQL> INSERT INTO DEPARTMENT VALUES(101,'SRINATH','HINDUPUR');
1 row created.
SQL> INSERT INTO DEPARTMENT VALUES(102,'SAINATH','ANANTAPUR');
1 row created.
SQL>
Here is your procedure:
SQL> create or replace PROCEDURE ADD_DEPARTMENT
2 (P_DID IN DEPARTMENT.DID%TYPE,
3 P_DNAME IN DEPARTMENT.DNAME%TYPE,
4 P_DLOC IN DEPARTMENT.DLOC%TYPE,
5 P_ERROR_MSG OUT VARCHAR2)
6 IS
7 BEGIN
8 INSERT INTO DEPARTMENT(DID,DNAME,DLOC)VALUES(P_DID,P_DNAME,P_DLOC);
9 COMMIT;
10 EXCEPTION
11 WHEN OTHERS THEN
12 P_ERROR_MSG:=SQLERRM;
13 END ADD_DEPARTMENT;
14 /
Procedure created.
SQL>
And lo! not only does it compile but it runs without error too.
SQL> set serveroutput on
SQL> declare
2 v varchar2(128);
3 begin
4 add_department(666, 'Area 51', 'Roswell', v);
5 end;
6 /
PL/SQL procedure successfully completed.
SQL> select * from department;
DID DNAME DLOC
---------- -------------------- --------------------
101 SRINATH HINDUPUR
102 SAINATH ANANTAPUR
666 Area 51 Roswell
SQL>
So once again I ask, what is the problem?
"PLS-00905: object SCOTT.ADD_DEPARTMENT is invalid"
In SQL*Plus:
Connect as SCOTT
alter procedure add_department compile;
show errors
Or apply the equivalent sequence for whatever IDE you use to write your code.